typescript - 为了保证类型安全, "as const"断言是这里唯一的解决方案吗?

标签 typescript

我有以下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>;
}

Playground link.

通过该实现,当我调用 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. :)

它有效。奇异的魔法万岁!! 🧙‍​​♂️✨🌈🦄


好的,希望有帮助;祝你好运!

Playground link to code

关于typescript - 为了保证类型安全, "as const"断言是这里唯一的解决方案吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60405701/

相关文章:

angular - Angular 为 4 的 formArray 内的 Formarray

typescript - 不能在 Typescript Map 中使用数字作为键?

typescript - 在 Typescript 中返回嵌套数组类型

typescript amd 模块无法编译

javascript - 类型错误 : Unable to get property 'ngMetadataName' of undefined or null reference on IE 10

reactjs - 类型 'Promise<(string[] | undefined)[]>' 缺少类型 'Etablissement[]' : length, pop、push、concat 等 29 个属性

reactjs - 使用样式化组件时如何保留原始 html 元素的属性?

reactjs - 如何在 TypeScript 中通过组件注入(inject)将 defaultProps 添加到通用功能组件?

javascript - 无法读取 PDF 组件中未定义的属性 'forEach'

typescript - 在 TypeScript 中,当类型是函数的参数时,有没有办法限制 Partial<T> 类型的额外/多余属性?