基于键大写的 TypeScript 类型

TypeScript types based on capitalization of a key

正在尝试向我正在使用的现有 JS 库添加类型。不幸的是,库有一个规则,即对象中值的类型在某种程度上是由其关联键的首字母大写决定的。我认为像下面这样的东西可能会起作用,但它不起作用。

type UppercaseLetters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
type LowercaseLetters = Lowercase<UppercaseLetters>;

type RefKey = `${UppercaseLetters}${string}`
type PropKey = `${LowercaseLetters}${string}`

// Define these types just so it compiles
type SomeRefType = number;
type SomePropType = boolean;

type Spec = {
  type: string
} & {
  [s in RefKey]: SomeRefType
} & {
  [s in PropKey]: SomePropType
};

这样编译,但是Spec变成的实际类型是:

type Spec = {
    type: string;
} & {} & {}

有什么想法吗?也许这种情况对于 TypeScript 来说太过分了。

示例对象:

const specObj: Spec = {
  type: 'Some string',
  Apple: 3,
  Orange: 6,
  lowerCaseKey: false,
  anotherOne: true
}

我删除了

type RefKey = `${UppercaseLetters}${string}`
type PropKey = `${LowercaseLetters}${string}`

并替换为 UppercaseLettersLowercaseLetters 类型

是你要找的吗?

Alateros in the comments, since typescript@4.4 you can use index signatures for template literals所述。

尽管您仍然必须确保 type 字段必须是必需的,并且可能具有与 lowercased 键类型不兼容的类型。所以你可以这样写 Spec 类型:

type Spec = {
  [K in RefKey | PropKey]: 'type' extends K 
      ? string 
      : K extends RefKey 
          ? SomeRefType 
          : K extends PropKey 
              ? SomePropType
              : never
} & {
  type: string
}

playground link