为什么我不能间接返回对象文字来满足 TypeScript 中的索引签名返回类型? [英] Why can't I indirectly return an object literal to satisfy an index signature return type in TypeScript?
问题描述
这三个函数似乎做同样的事情,但最后一个是错误的.为什么会这样?
These three functions seem to do the same thing, but the last one is an error. Why is this the case?
interface StringMap {
[key: string]: string;
}
function a(): StringMap {
return { a: "1" }; // OK
}
function b(): StringMap {
var result: StringMap = { a: "1" };
return result; // OK
}
function c(): StringMap {
var result = { a: "1" };
return result; // Error - result lacks index signature, why?
}
推荐答案
这种行为正在消失.
从 TypeScript 1.8 之后的任何版本开始(或者现在,如果您使用的是前沿编译器),当类型的原始表达式是对象字面量时,您将不再看到此错误.
This behavior is going away.
Starting at whatever release comes after TypeScript 1.8 (or right now if you're using the bleeding-edge compiler), you will no longer see this error when the originating expression for a type is an object literal.
参见 https://github.com/Microsoft/TypeScript/pull/7029
索引签名和对象字面量在 TypeScript 中表现得特别好.来自规范第 4.5 节,对象文字:
Index signatures and object literals behave specially in TypeScript. From spec section 4.5, Object Literals:
当对象字面量由包含T 类型的字符串索引签名,对象的结果类型文字包括一个字符串索引签名,其扩展形式为T 的最佳公共类型和声明中的属性类型对象字面量.
When an object literal is contextually typed by a type that includes a string index signature of type T, the resulting type of the object literal includes a string index signature with the widened form of the best common type of T and the types of the properties declared in the object literal.
这一切意味着什么?
上下文类型发生在表达式的 上下文 暗示其类型可能是什么时.例如,在这个初始化中:
Contextual typing occurs when the context of an expression gives a hint about what its type might be. For example, in this initialization:
var x: number = y;
表达式 y
获得 number
的上下文类型,因为它正在初始化该类型的值.在这种情况下,没有什么特别的事情发生,但在其他情况下会发生更有趣的事情.
The expression y
gets a contextual type of number
because it's initializing a value of that type. In this case, nothing special happens, but in other cases more interesting things will occur.
最有用的情况之一是函数:
One of the most useful cases is functions:
// Error: string does not contain a function called 'ToUpper'
var x: (n: string) => void = (s) => console.log(s.ToUpper());
编译器如何知道 s
是一个字符串?如果您自己编写该函数表达式,s
将是 any
类型,并且不会发出任何错误.但是因为函数是上下文类型由x
的类型,参数s
获取类型string
.很有用!
How did the compiler know that s
was a string? If you wrote that function expression by itself, s
would be of type any
and there wouldn't be any error issued. But because the function was contextually typed by the type of x
, the parameter s
acquired the type string
. Very useful!
索引签名指定对象由字符串或数字索引时的类型.当然,这些签名是类型检查的一部分:
An index signature specifies the type when an object is indexed by a string or a number. Naturally, these signatures are part of type checking:
var x: { [n: string]: Car; };
var y: { [n: string]: Animal; };
x = y; // Error: Cars are not Animals, this is invalid
缺少索引签名也很重要:
The lack of an index signature is also important:
var x: { [n: string]: Car; };
var y: { name: Car; };
x = y; // Error: y doesn't have an index signature that returns a Car
希望上面的两个片段很明显应该会导致错误.这导致我们...
Hopefully it's obvious that the above two snippets ought to cause errors. Which leads us to...
假设对象没有索引签名的问题是你无法用索引签名初始化一个对象:
The problem with assuming that objects don't have index signatures is that you then have no way to initialize an object with an index signature:
var c: Car;
// Error, or not?
var x: { [n: string]: Car } = { 'mine': c };
解决方案是,当对象字面量由具有索引签名的类型在上下文中键入时,该索引签名被添加到对象字面量的类型如果匹配.例如:
The solution is that when an object literal is contextually typed by a type with an index signature, that index signature is added to the type of the object literal if it matches. For example:
var c: Car;
var a: Animal;
// OK
var x: { [n: string]: Car } = { 'mine': c };
// Not OK: Animal is not Car
var y: { [n: string]: Car } = { 'mine': a };
将它们放在一起
让我们看看问题中的原始函数:
Putting It All Together
Let's look at the original functions in the question:
function a(): StringMap {
return { a: "1" }; // OK
}
好的,因为 return
语句中的表达式是由函数的返回类型上下文类型化的.对象字面量 {a: "1"}
的唯一属性有一个字符串值,因此可以成功应用索引签名.
OK, because expressions in return
statements are contextually typed by the return type of the function. The object literal {a: "1"}
has a string value for its sole property, so the index signature can be successfully applied.
function b(): StringMap {
var result: StringMap = { a: "1" };
return result; // OK
}
好的,因为显式类型变量的初始值设定项是根据变量类型进行上下文类型化的.和以前一样,索引签名被添加到对象字面量的类型中.
OK, because the initializers of explicitly-typed variables are contextually typed by the type of the variable. As before, the index signature is added to the type of the object literal.
function c(): StringMap {
var result = { a: "1" };
return result; // Error - result lacks index signature, why?
}
不行,因为result
的类型没有索引签名.
Not OK, because result
's type does not have an index signature.
这篇关于为什么我不能间接返回对象文字来满足 TypeScript 中的索引签名返回类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!