简体   繁体   English

为什么我不能间接返回一个对象文字来满足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?
}

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. 从TypeScript 1.8之后的任何版本开始(或者现在,如果你使用的是最前沿的编译器),当一个类型的原始表达式是一个对象文字时,你将不会再看到这个错误。

See https://github.com/Microsoft/TypeScript/pull/7029 请参阅https://github.com/Microsoft/TypeScript/pull/7029


The Old Answer for The Old Compilers 旧编译器的旧答案

Index signatures and object literals behave specially in TypeScript. 索引签名和对象文字在TypeScript中特别表现。 From spec section 4.5, Object Literals: 从规范4.5节,对象文字:

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. 当对象文字由包含类型T的字符串索引签名的类型进行上下文类型化时,对象文字的结果类型包括字符串索引签名,其中扩展形式为最常见的T类型和声明的属性类型在对象文字中。

What does this all mean? 这是什么意思呢?

Contextual Typing 上下文打字

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;

The expression y gets a contextual type of number because it's initializing a value of that type. 表达式y获取上下文类型的number因为它正在初始化该类型的值。 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());

How did the compiler know that s was a string? 编译器是如何知道s是字符串的? If you wrote that function expression by itself, s would be of type any and there wouldn't be any error issued. 如果您自己编写该函数表达式,则s将是any类型,并且不会发出任何错误。 But because the function was contextually typed by the type of x , the parameter s acquired the type string . 但是因为函数是由x的类型在上下文中键入的,所以参数s获取了类型string Very useful! 很有用!

Index Signatures 索引签名

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... 这导致我们......

Index Signatures and Contextual Typing 索引签名和上下文键入

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
}

OK , because expressions in return statements are contextually typed by the return type of the function. 好的 ,因为return语句中的表达式是由函数的返回类型在上下文中键入的。 The object literal {a: "1"} has a string value for its sole property, so the index signature can be successfully applied. 对象文字{a: "1"}具有其唯一属性的字符串值,因此可以成功应用索引签名。

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?
}

Not OK , because result 's type does not have an index signature. 不行 ,因为result的类型没有索引签名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM