Typescript 通用函数允许任意键
为什么下面的代码编译成功?由于Typescript 通用函数允许任意键,typescript,Typescript,为什么下面的代码编译成功?由于bar不是MyState的一部分,我希望它会生成一个编译器错误 type MyState = { foo: number; }; type Reducer<T> = (state: T) => T; const wtf: Reducer<MyState> = (state) => { return { foo: 123, bar: 123 }; // `bar` isn't part of MyState }; typem
bar
不是MyState
的一部分,我希望它会生成一个编译器错误
type MyState = { foo: number; };
type Reducer<T> = (state: T) => T;
const wtf: Reducer<MyState> = (state) => {
return { foo: 123, bar: 123 }; // `bar` isn't part of MyState
};
typemystate={foo:number;};
减速器类型=(状态:T)=>T;
常量wtf:Reducer=(状态)=>{
return{foo:123,bar:123};/`bar`不是MyState的一部分
};
TypeScript中的类型兼容性基于结构子类型。结构类型是一种仅基于其成员关联类型的方法。这与标称类型形成对比
为了检查y是否可以分配给x,编译器检查x的每个属性,以在y中找到相应的兼容属性。在这种情况下,y必须有一个名为name的字符串成员。确实如此,因此允许分配。请注意,y有一个额外的location属性,但这不会创建错误。检查兼容性时,只考虑目标类型(在本例中命名)的成员
因此,在您的示例中,{foo:123,bar:123}
满足了一个foo
这是一个数字的要求,并且为了类型兼容性,额外的bar
被忽略
注意:另请参见crashmstr的回答是正确的,但值得解释一下为什么这种情况与您确实会出错的情况不同 对象文字仅在特定情况下导致额外的属性错误 在这种情况下:
var x: MyState = { foo: 10, bar: 20 };
类型系统执行以下步骤:
- 检查MyState是否为有效类型(它是)
- 检查初始值设定项是否有效:
- 初始值设定项的类型是什么?
- 它是新对象类型
{foo:10,bar:20}
- 它是新对象类型
- 它可分配给MyState吗?
- 是否有
属性?foo
- 对
- 它的类型匹配吗?
- 是(
->10
)number
- 是(
- 新类型是否有其他属性?
- 对
- 错误
- 对
- 是否有
- 初始值设定项的类型是什么?
// Error
var x: MyState = { foo: 10, bar: 20 };
及
因为一旦将对象文本分配到x1
,它的新鲜度就会消失
您的示例也面临同样的命运——一旦对象文本成为函数返回类型的一部分,它的新鲜度就消失了。这也解释了如果函数表达式上有返回类型注释,则错误会再次出现的原因。为什么会出现此错误。MyState只需要foo,如果它有更多,它仍然满足MyState的定义。@ErikPhilips编译器会对此抱怨:
const MyState:MyState={foo:123,bar:123}代码>并会说“Object literal可能只指定已知属性,而'MyState'类型中不存在'bar'。”那么编译器为什么会抱怨以下问题const wtf2(state:MyState):MyState=>{return{foo:123,bar:123};
它说,“Object literal只能指定已知的属性,而'bar'在类型'MyState'中不存在。”另请参见@crashmstr I downvoted,因为编译器会在我们使用同一函数的非泛型形式时发出抱怨。答案没有说明为什么泛型形式允许未知属性,而非泛型形式不允许未知属性。具体来说,有一种情况是,对象文本保持在更高的标准,我不同意现在,在指定的文档中,这也不是问题的一部分,只是一个注释。问题的函数实现返回一个对象文本,因此对象文本是问题的一部分,因为它当前的状态。除了名义类型之外,是否有计划允许对像这样的情况吗?这不是一个健全的缺陷。没有观察到错误的类型;函数返回一个正确的子类型。对不起,我可能天真地使用了术语“声音”。我只是试图防止在我的缩减器中输入错误,但在当前的类型系统中,这是很困难的。
// OK
var x1 = { foo: 10, bar: 20 };
var x2: MyState = x1;