第 27 期 - Object Property Order's Impact on TypeScript Type Inference
logoFRONTALK AI/11月19日 16:30/阅读原文

摘要

阐述了 TypeScript 中对象属性顺序对类型推断有影响,以一个函数为例展示正常与异常情况,提到 TypeScript 4.7 版本对此的改进,还探讨了 NoInfer 无法解决相关问题。

一、函数示例中的正常类型推断

在示例中创建了一个函数process,它接受一个对象作为参数,对象包含produceconsume两个属性。

const process = <T>(obj: {
    produce: (input: string) => T;
    consume: (t: T) => void;
}) => {
    const value = obj.produce("abc");
    obj.consume(value);
};

当按照正常顺序定义produceconsume属性时,如:

process({
    produce: (input) => Number(input),
    consume: (output) => console.log(output), (parameter) output: number
});

TypeScript 能够正确推断produce返回值的类型并传递给consume。并且可以适用于不同类型的值,例如:

process({
    produce: (input) => input + "hello",
    consume: (output) => console.log(output), (parameter) output: string
});
process({
    produce: (input) => ({ value: input }),
    consume: (output) => console.log(output), (parameter) output: {
        value: string;
    }
});

二、属性顺序改变后的类型推断问题

当用户将consume放在produce之前时,就会出现问题:

process({
    consume: (output) => console.log(output), (parameter) output: unknown
    produce: (input) => Number(input),
});

此时TypeScriptoutput视为unknown,尽管produce函数明显返回一个数字。这是因为自TypeScript 4.7版本起,会根据属性顺序进行类型推断,这一改变是为了解决一些长期存在的与上下文敏感函数相关的漏洞。

三、NoInfer 无法解决该问题

有人可能会想是否可以使用NoInfer来解决这个问题,毕竟NoInfer用于强制TypeScript避免对某些目标进行推断。但是:

const process = <T>(obj: {
    produce: (input: string) => T;
    consume: NoInfer<(t: T) => void>;
}) => {
    const value = obj.produce("abc");
    obj.consume(value);
};
process({
    consume: (output) => console.log(output), (parameter) output: unknown
    produce: (input) => Number(input),
});

结果仍然是unknown,令人沮丧。

 

扩展阅读

Made by 捣鼓键盘的小麦 / © 2025 Front Talk 版权所有