我有以下objectify
实现:
type MappedObject<T extends readonly string[]> = {
[key in T[number]]: number;
};
function objectify<T extends readonly string[]>(array: T): MappedObject<T> {
return array.reduce(
(acc, term, index) => ({ ...acc, [term]: index }),
{}
) as MappedObject<T>;
}
通过该实现,当我调用 objectify
断言第一个传递的参数为 as const
时,它会返回一个类型安全对象,如您可以在以下示例中看到:
const obj = objectify(['a', 'b', 'c'] as const); // Notice the `as const` assertion.
obj.a;
obj.b;
obj.c;
obj.d; // Error! My code is safe. :)
Example of this "safe" behavior in the playground.
然而,遗憾的是,当我删除 as const
断言时,类型安全性就消失了,这使我的代码容易出错。由于“不安全”的返回类型,我什至可以访问返回对象中不存在的属性,如以下示例的最后一行所示 (obj.d
):
const obj = objectify(['a', 'b', 'c']); // No more `as const` assertion.
obj.a;
obj.b;
obj.c;
obj.d; // No errors! My code is error prone. :(
Example of this "unsafe" behavior in the playground.
问题是:使用 as const
断言是保证类型安全的唯一方法吗? 还有另一种方法可以实现同样的“安全”行为吗?
我的目标是充分保证函数实现中的代码安全,避免调用函数时出现任何断言。我想通过仅更改函数实现而不是其调用来使以下代码安全。
// What I can do:
const obj = objectify(['a', 'b', 'c'] as const);
// What I want to be able to do:
const obj = objectify(['a', 'b', 'c']);
///// `obj` would be "safe" here.
最佳答案
我在这里感受到你的痛苦。理想情况下,会有一个功能允许您注释函数,以便它处理某些参数 as const
而不要求调用者这样做。我已经在 microsoft/TypeScript#30680 中提出了这个要求;如果你想看到这种情况发生,你可能想去那里给它一个👍,但目前它还不是一个功能。
幸运的是,有一些方法可以编写函数签名,为编译器提供提示来指导这样的推理;只是它们很难理解,而且看起来像是奇怪的魔法,而不是直接传达开发人员的意图。
具体情况下推断string literal types ,实现这种情况的一种方法是使用限制为 string
的类型参数。 (即 S extends string
)而不是 string
本身(参见 microsoft/TypeScript#10676 ):
function objectify<T extends readonly S[], S extends string>(array: T): MappedObject<T> {
return array.reduce(
(acc, term, index) => ({ ...acc, [term]: index }),
{}
) as MappedObject<T>;
}
这看起来有点没用,特别是因为 S
可能会被推断为 string
。但至关重要的是,这会导致 T
的类型推断为Array<"a" | "b" | "c">
而不是Array<string>
:
const stillSafeObj = objectify(['a', 'b', 'c']); // No more `as const` assertion.
stillSafeObj.a;
stillSafeObj.b;
stillSafeObj.c;
stillSafeObj.d; // Error! My code is safe. :)
它有效。奇异的魔法万岁!! 🧙♂️✨🌈🦄
好的,希望有帮助;祝你好运!
关于typescript - 为了保证类型安全, "as const"断言是这里唯一的解决方案吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60405701/