假定有以下功能:

export const createLetterGroups = (dynamicKey: string) => {
  const letters = ['A', 'B', 'C'];

  return letters.map(letter => ({
    letter,
    [dynamicKey]: [{ test: 'string1' }, { test: 'string2' }]
  }));
};

TypeScrip正在推断以下返回类型:

const createLetterGroups: (dynamicKey: string) => {
    [x: string]: string | {
        test: string;
    }[];
    letter: string;
}[]

为什么它将动态属性键入为:

string | {
        test: string;
    }[]

而不是仅仅:

{
    test: string;
}[]

推荐答案

对于动态属性名称,TypeScrip处理类型推断的方式不同.我认为这种情况的原因本质上是,你的dynamicKey串有可能实际上是be,'letter'串.

从技术上讲,这与函数返回的类型无关,只需一个变量赋值即可复制相同的行为:

declare const num: number;
declare const str: string;

/**
 * Inferred type:
 * ```
 * {
 *   [x: string]: number | string;
 *   num: number;
 * }
 * ```
 */
const bar = {
  num,
  [str]: str,
};

TypeScript Playground

考虑这样的情况,在本例中,动态属性的名称是num.在这种情况下,结果对象将是{ num: 'num' },因此为了考虑这种可能性,TypeScrip必须推断动态键的类型可能是字符串.

然而,就我所知,TypeScrip似乎不会根据属性的顺序更改其推断类型.而JAVASCRIPT does在创建对象时关心属性的顺序,至少在存在重复键的情况下是如此--最后一个键会覆盖任何先前的键.

如果您知道您正在构造的对象的类型肯定不同于类型脚本所推断的类型,那么您可能希望使用type assertion来告诉编译器它还不知道的事情.

尽管我通常建议谨慎使用类型断言,因为如果它们不是基于良好的假设,那么使用它们的方式可能会损害类型脚本的类型判断.它们当然有一席之地,也是有用的工具,但重要的是要意识到它们的缺点.


下面是一个可运行的示例,显示了我在上面提到的{ num: 'num' }个示例:

const num = 3;
const str = 'num';

const foo = ((str: string, num: number) => {
  const bar = {
    num,
    [str]: str,
  };

  return bar;
})(str, num);

console.log(foo);

TypeScript Playground

Typescript相关问答推荐

从接口创建类型安全的嵌套 struct

Angular 17 -如何在for循环内创建一些加载?

使用Angular和API请求在CRUD操作后更新客户端数据的良好实践

类型脚本基于数组作为泛型参数展开类型

在TypeScrip的数组中判断模式类型

缩小并集子键后重新构造类型

是否可以针对联合类型验证类型属性名称?

有没有可能为这样的函数写一个类型?

已解决:如何使用值类型限制泛型键?

为什么&;(交集)运算符会删除不相交的属性?

Typescript 类型守卫一个类泛型?

->;Boolean类型的键不能分配给类型Never

为什么S struct 类型化(即鸭子类型化)需要非严格类型联合?

如何使这种一对一关系在旧表上起作用?

在正常函数内部调用异步函数

是否可以通过映射类型将函数参数约束为预定义类型?

如何为对象数组中的每个条目推断不同的泛型

如何提取具有索引签名的类型中定义的键

React Context TypeScript错误:属性';firstName';在类型';iCards|iSearch';

使用泛型时记录无法建立索引