Typescript 不同范围变量的类型推断
考虑以下代码(在TypeScript 3.2.2中运行): 由于Typescript 不同范围变量的类型推断,typescript,tsc,Typescript,Tsc,考虑以下代码(在TypeScript 3.2.2中运行): 由于test的返回类型及其签名不匹配,因此无法编译: error TS2322: Type '"successful"' is not assignable to type 'IResult<"hello">'. 生成预期的返回类型“成功”|“失败” 使用让: function test(): typeof status { let status = 'hello'; // notice the let here
test
的返回类型及其签名不匹配,因此无法编译:
error TS2322: Type '"successful"' is not assignable to type 'IResult<"hello">'.
生成预期的返回类型“成功”|“失败”
使用让
:
function test(): typeof status {
let status = 'hello'; // notice the let here
return 'successful';
}
这会编译,但返回类型为string
,内部定义将再次使用
我希望tsc
使用status
,在这两种情况下,无论test
中存在什么声明,它都是在作用域中定义的最高级别来评估其返回类型为什么出现上述行为?这应该与tsc
如何决定使用哪些变量进行类型推断有关。这里有12种情况:
(常量、let、var)*(全局、局部)*(显式字符串并集、推断字符串)
TL;博士
简单方法:
- 如果显式地在外部范围中指定类型,则结果总是相同的:union of
“ok”|“no”
- 由于内部
和let
可用于返回位置的const
,因此它们对外部声明进行阴影处理typeof
- 内部
对于返回类型位置的var
不可用(无论出于何种原因)typeof
- 如果你想推断:<代码>让和<代码> var >代码>将考虑类型为“代码>字符串”,并且<代码> const 将键入精确的[不变的原始]值。
供参考的个案清单:
你的问题是什么?谢谢你完整的回答-很容易理解。我用组合框更新了答案,当内部出现阴影时。
function test(): typeof status {
var status = 'hello'; // notice the var here
return 'successful';
}
function test(): typeof status {
let status = 'hello'; // notice the let here
return 'successful';
}
// Infer, Inner
function test_inner_let(): typeof status01 { // type is string
let status01 = 'ok'; // let is mutable, so type is only string
return 'lol';
}
function test_inner_const(): typeof status02 { // type is 'ok'
const status02 = 'ok'; // const allows to specify type to exact 'ok'
return 'lol'; // error, 'lol' is not assignable to 'ok'
}
function test_inner_var(): typeof status03 { // type is any, TS warning: status03 not found
var status03 = 'ok'; // var is mutable, so type is string
return 'lol';
}
// Explicit, Inner
function test_inner_let_t(): typeof status11 { // type is union 'ok'|'no'
let status11: 'ok' | 'no' = 'ok';
return 'lol'; // error, 'lol' is not assignable to 'ok'|'no'
}
function test_inner_const_t(): typeof status12 { // type is union 'ok'|'no'
const status12: 'ok' | 'no' = 'ok';
return 'lol'; // error, 'lol' is not assignable to 'ok'|'no'
}
function test_inner_var_t(): typeof status13 { // type is any, TS warning: status13 not found
var status13: 'ok' | 'no' = 'ok';
return 'lol';
}
// Explicit, Outer - everything works the same
let status21: 'ok' | 'no' = 'ok';
function test_outer_let_t(): typeof status21 { // type is union 'ok'|'no'
return 'lol'; // error, 'lol' is not assignable to 'ok'|'no'
}
const status22: 'ok' | 'no' = 'ok';
function test_outer_const_t(): typeof status22 { // type is union 'ok'|'no'
return 'lol'; // error, 'lol' is not assignable to 'ok'|'no'
}
var status23: 'ok' | 'no' = 'ok';
function test_outer_var_t(): typeof status23 { // type is union 'ok'|'no'
return 'lol'; // error, 'lol' is not assignable to 'ok'|'no'
}
// Infer, Outer
let status31 = 'ok'; // type is string
function test_outer_let(): typeof status31 { // type is string
return 'lol';
}
const status32 = 'ok'; // const allows to specify type to exact 'ok'
function test_outer_const(): typeof status32 { // type is 'ok'
return 'lol'; // error, 'lol' is not assignable to 'ok'
}
var status33 = 'ok'; // var is mutable, so type is string
function test_outer_var(): typeof status33 { // type is string
return 'lol';
}
// (Explicit, Outer const) + (Implicit, Inner)
const status41: 'ok' | 'no' = 'ok';
function test_combo_let(): typeof status41 { // type is string, inner let took preference
let status41 = 'ok';
return 'lol';
}
const status42: 'ok' | 'no' = 'ok';
function test_combo_const(): typeof status42 { // type is 'sorry', inner const took preference
const status42 = 'sorry';
return 'lol'; // error, 'lol' is not assignable to 'sorry'
}
const status43: 'ok' | 'no' = 'ok';
function test_combo_var(): typeof status43 { // type is union 'ok'|'no', var is not bubling up
var status = 'whatever';
return 'lol'; // error, 'lol' is not assignable to 'ok'|'no'
}