【问题标题】:Why can't I indirectly return an object literal to satisfy an index signature return type in TypeScript?为什么我不能间接返回对象文字以满足 TypeScript 中的索引签名返回类型?
【发布时间】:2016-02-17 09:00:00
【问题描述】:

这三个函数看似做同样的事情,但最后一个是错误的。为什么会这样?

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】:

    这种行为正在消失。

    从 TypeScript 1.8 之后的任何版本开始(或者现在,如果您使用的是最先进的编译器),当类型的原始表达式是对象文字时,您将不再看到此错误。

    https://github.com/Microsoft/TypeScript/pull/7029


    旧编译器的旧答案

    索引签名和对象字面量在 TypeScript 中的行为特别。从规范第 4.5 节,对象文字:

    当对象字面量由包含 T 类型的字符串索引签名,对象的结果类型 文字包括一个字符串索引签名,其扩展形式为 T 的最佳常见类型和在声明中声明的属性的类型 对象字面量。

    这一切意味着什么?

    上下文输入

    当表达式的 context 提示其类型可能是什么时,就会发生上下文类型。例如,在这个初始化中:

    var x: number = y;
    

    表达式y 获得number 的上下文类型,因为它正在初始化该类型的值。在这种情况下,没有什么特别的事情发生,但在其他情况下会发生更有趣的事情。

    最有用的案例之一是函数:

    // 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 类型。很有用!

    索引签名

    索引签名指定对象被字符串或数字索引时的类型。自然,这些签名是类型检查的一部分:

    var x: { [n: string]: Car; };
    var y: { [n: string]: Animal; };
    x = y; // Error: Cars are not Animals, this is invalid
    

    没有索引签名也很重要:

    var x: { [n: string]: Car; };
    var y: { name: Car; };
    x = y; // Error: y doesn't have an index signature that returns a Car
    

    希望以上两个 sn-ps 显然应该会导致错误。这导致我们...

    索引签名和上下文类型

    假设对象没有索引签名的问题是您无法使用索引签名初始化对象:

    var c: Car;
    // Error, or not?
    var x: { [n: string]: Car } = { 'mine': c };
    

    解决方案是,当对象字面量由具有索引签名的类型在上下文中键入时,该索引签名被添加到对象字面量的类型中如果匹配。例如:

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

    把它们放在一起

    我们看一下问题中的原始函数:

    function a(): StringMap {
        return { a: "1" }; // OK
    }
    

    OK,因为return 语句中的表达式是由函数的返回类型在上下文中键入的。对象字面量{a: "1"} 的唯一属性有一个字符串值,因此可以成功应用索引签名。

    function b(): StringMap {
        var result: StringMap = { a: "1" };
        return result; // OK
    }
    

    OK,因为显式类型变量的初始值设定项是由变量的类型上下文类型化的。和以前一样,索引签名被添加到对象字面量的类型中。

    function c(): StringMap {
        var result = { a: "1" };
        return result; // Error - result lacks index signature, why?
    }
    

    不行,因为result的类型没有索引签名。

    【讨论】:

    • 这解决了我对打字稿索引器的困惑。感谢您的描述性回答。
    • 在将对象传递给函数时出现此错误,我假设它是同一个问题?你有没有机会帮助我理解如何处理它? stackoverflow.com/questions/34668914/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-21
    • 2011-06-28
    • 2019-09-12
    • 2021-05-01
    • 2017-08-04
    • 2021-03-28
    • 2018-06-13
    相关资源
    最近更新 更多