TypeScript:告诉对象它可以拥有哪些键和值

TypeScript: Tell object which keys and values it can have

我有一个代表某些常量之一的类型。每种类型也有特定的回调函数。

type MyType = 'A' | 'B' | 'C';

// Same for 'B', 'C' etc.
type callbackForA = (result: ResultForA) => void;

ResultForA 是属于 A.

的特定对象

我想为 可能有 键的对象创建一个 TypeScript typeinterface(我们称之为 MagicType)对于这些 MyType 个常量中的每一个。这些键中的每一个的值可以是 true(或隐式 undefined 因此 "可能有")或可能是具有特定调用签名的回调函数基于类型。

以下应该是有效的 MagicType 对象:

const myObject: MagicType = {
  'A': true | (result: ResultForA) => void,
  'C': true;
}

其中 B 未配置,并且 C 不接受回调。

以下应该是 MagicType 的无效对象。

const myObject: MagicType = {
  'A': true | (result: ResultForB) => void;
  'FOO': true
}

因为 A 有错误的回调函数 (result: ResultForB) => void 并且 FOO 不是 MyType 的有效选项。

如何实现这样的类型?


我尝试的是像这样扩展 Result 类型:

type CallbackFunctionVariadicAnyReturn = (...args: any[]) => any

interface MagicType extends Record<MyType, true | CallbackFunctionVariadicAnyReturn>;

不幸的是,它既没有检测到多余的键,例如 FOO,也没有检测到错误的回调函数。


额外的想法/问题:

是否还有一种方法可以将回调与每个 MyType 值紧密耦合?也许是这样的元组?

type MyTypePairs = ['A', (result: ResultForA) => void] | ['B', // ...
type MagicType = {
    'A': boolean | (result: ResultForA) => void,
    'B': undefined,
    'C': boolean,
}

所做的是为三个键中的每一个添加类型注释,并且由于 TS 不允许使用列出的键以外的任何键,因此您不能使用 'FOO' 键,并且回调上的注释意味着您不能在 a.

上执行 (result: ResultForB) => void 回调

TS Playground

// define your types
type ResultForA = { a: string };

interface ResultCollection {
  A: ResultForA;  // can use named type alias
  B: { b: boolean }; // or simply inline your result types
  C: { c: number };
}

// Bonus thought / question:
type ResultFunc<K extends keyof ResultCollection> = (result: ResultCollection[K]) => void;

// Tell object which keys and values it can have
type MagicType = Partial<{[K in keyof ResultCollection]: ResultFunc<K> | boolean}>;


// examples

const good1: MagicType = { // ok
  A: true,
  B: (r: { b: boolean }) => {
    console.log(r);
  },
};

const good2: MagicType = { // ok
  A: (r: { a: string }) => {},
  B: (r: { b: boolean }) => {
    console.log(r);
  },
  C: false
};

const bad1: MagicType = {
  Foo: true, // error
}

const bad2: MagicType = { 
  B: (r: { c: number }) => { // error
    console.log('not a good b');
  },
};

为此,您需要创建映射数据结构,它将每个允许的键映射到某个 type/value。 考虑这个例子:


type MyMap = {
  A: "#A",
  B: '#B',
  C: '#C'
}

type MyType = keyof MyMap


type ResultForA = '#A'
type ResultForB = '#B'
type ResultForC = '#C'

type MagicType<Dict> = {
  [Prop in keyof Dict]?: true | ((value: Dict[Prop]) => void)
}

type Result = MagicType<MyMap>


Playground

类型 MyMap 是地图数据结构,您可能已经猜到了。

MagicType 是在 mapped types

的帮助下构建的