网站搜索

字典 - TypeScript 指定 Map 的值类型但不指定键类型


我想在一个映射上强制执行通用类型,使得每个键的每个值都是特定类型(在此示例中为 A),但我不想覆盖底层默认的键类型。在下面的示例中,如果我将 MY_MAP 的类型指定为 Record<string, A>,MyMapKeys 类型会从期望的键联合 'unknown' | 'error' 变为 string。如何在强制映射的通用值类型为 A 的同时保留 MY_MAP 的只读键?

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;

答案#1

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)

查看游乐场


在 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',
  },
});

查看游乐场