【问题标题】:Typescript function accepting invalid argument with no error打字稿函数接受无效参数且没有错误
【发布时间】:2017-01-31 19:50:45
【问题描述】:

我试图了解 Typescript 提供的类型安全的程度。我遇到了一种情况,我预计会出错,但 Typescript 没有抱怨。

我定义了一个函数,其参数与某个接口匹配。然后我用一些不匹配的参数调用函数。这是代码(or in playground):

interface ArgumentInterface {
    [key: number]: string
}

interface InvalidArgumentInterface {
    [key: string]: number
}

interface InvalidArgumentInterface2 {
    foo: number
}

function myFunction(arg: ArgumentInterface) {
    // function body
}

let validArgument: ArgumentInterface = {};
validArgument[5] = 'I am a string';

let invalidArgument: InvalidArgumentInterface = {
    foo: 42
};

let invalidArgument2: {foo: number} = {
    foo: 42
};

let invalidArgument3: InvalidArgumentInterface2 = {
    foo: 42
};

let invalidArgument4 = {
    foo: 42
};

myFunction(validArgument); // no typescript error, as expected
myFunction(invalidArgument); // typescript error, as expected
myFunction(invalidArgument2); // no typescript error!
myFunction(invalidArgument3); // typescript error, as expected
myFunction(invalidArgument4); // no typescript error!

当我的参数变量显式声明一个不兼容的接口时,我得到了预期的 Typescript 错误。但是当我的参数变量声明一个类型文字(没有接口)或根本没有声明任何类型时,Typescript 根本不会抱怨,尽管我预计会出错。

我已将“noImplicitAny”标志设置为 true。

谁能解释这种行为?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您没有收到以下错误:

    myFunction(invalidArgument2);
    myFunction(invalidArgument4);
    

    因为它们的类型是{ foo: number; },并且与ArgumentInterface的定义不矛盾,所以一个值可以是两者:

    let a = {
        1: "one",
        2: "two",
        foo: 4
    }
    

    这里用数字索引的有一个字符串值,但 foo 索引有一个数字值。

    如果ArgumentInterface 是:

    interface ArgumentInterface {
        [key: number]: string;
        [key: string]: string;
    }
    

    然后你会得到你期望的错误。

    【讨论】:

    • 我想我发现了我的误解:为 [key: number] 定义索引签名不会阻止添加字符串键,它只会限制值类型 如果键是号码 ?对吗?
    • 是的,似乎是这样。但反过来也行不通。另外,您应该知道 js 对象中的键是 always 字符串。如果您传递一个数字,它将被转换为一个字符串。如果您真的想要数字和字符串之间的映射,请使用 Map
    【解决方案2】:

    这是因为TypeScript uses structural typing(如 Ocaml)。

    invalidArgument2invalidArgument4 在结构上都与 ArgumentInterface 兼容,因此,TypeScript 很乐意接受它们。

    【讨论】:

    • 不,它们不相等。 ArgumentInterface{ [k: number]: string } 类型,而另外两个是 { foo: number } 类型。这些是不同的结构。
    • 将这个词替换为“兼容”,在我链接到的文档中使用。
    • 嗯,兼容更有意义。不过,我想说两者之间没有冲突。
    猜你喜欢
    • 1970-01-01
    • 2020-12-15
    • 2022-01-26
    • 2017-08-08
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多