TypeScript指定Map的值类型但不指定键类型

Noo*_*ath 2 dictionary types typescript

我想在映射上强制执行通用类型,以便每个键的每个值都是特定类型(在本例中A),但我不想覆盖底层默认键类型。MY_MAP在下面的示例中,如果我指定to be的类型Record<string, A>,则MyMapKeys类型从所需的键联合更改'unknown' | 'error'string。如何保留只读键,MY_MAP同时强制映射的通用值类型为A

type A = {
  name: string;
  description: string;
};

// MY_MAP must be a map of readonly string keys and type A values
const MY_MAP = {
  unknown: {
    name: 'unknown',
    description: 'unknown',
  },
  error: {
    name: 'error',
    // should display error: missing property "description"
  },
} as const;

// I want the following to be 'unknown' | 'error' not string
type MyMapKeys = keyof typeof MY_MAP;
Run Code Online (Sandbox Code Playgroud)

Ale*_*yne 6

Typescript 4.9(截至 2022 年 10 月 5 日目前处于测试阶段)

为此有一个新功能,称为运算satisfies符。

这允许您声明一个受类型限制的值,并且可以推断为更具体的类型。

const MY_MAP = {
  unknown: {
    name: 'unknown',
    description: 'unknown',
  },
  error: {
    name: 'error',
  },
} as const satisfies Record<string, A>;
// Type '{ readonly unknown: { readonly name: "unknown"; readonly description: "unknown"; }; readonly error: { readonly name: "error"; }; }' does not satisfy the expected type 'Record<string, A>'.
//  Property 'error' is incompatible with index signature.
//    Property 'description' is missing in type '{ readonly name: "error"; }' but required in type 'A'.(1360)
Run Code Online (Sandbox Code Playgroud)

查看游乐场


在 Typescript 4.8 或更低版本中

解决这个问题的方法一直是使用通用的恒等函数。

function makeMap<T extends Record<string, A>>(map: T): T {
  return map
}

// MY_MAP must be a map of readonly string keys and type A values
const MY_MAP = makeMap({
  unknown: {
    name: 'unknown',
    description: 'unknown',
  },
  error: {
    // Property 'description' is missing in type '{ name: string; }' but required in type 'A'.(2741)
    name: 'error',
  },
});
Run Code Online (Sandbox Code Playgroud)

查看游乐场