首页 > 解决方案 > 具有动态静态字段的函数

问题描述

我需要使用泛型类型的动态静态字段为函数编写一个类型

interface WithStatic<P, T extends string[]> {
  (props: P): void;
  [K in T]: WithStatic<P, T>; // TS Error: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
}

游乐场链接

如果我将动态字段移得更深(将其放到另一个字段中),则一切正常:

interface WithStatic<P, T extends string> {
  (props: P): void;
  options: {
    [K in T]: WithStatic<P, T>;
  };
}

游乐场链接

示例用法:

const withStatic = (props => {}) as WithStatic<{}, 'maybe' | 'ready'>;

然后输入

withStatic.options.

显示maybeready

在此处输入图像描述

如何改为在接口的根级别定义动态类型?

编辑

Playground 链接我在结果中得到的内容

标签: typescripttypescript-typingstyping

解决方案


映射类型不能包含除映射表达式(即[K in T]: ...)之外的任何其他声明。它也不能出现在界面中。

考虑到这一点,您将需要在类型别名中使用交集来描述您想要的类型。这将起作用:

type WithStatic<P, T extends string[]> = {
  (props: P): void;
} & {
  [K in T[number]]: WithStatic<P, T>; 
}

let c = ((p: {}) => 1) as any as WithStatic<{}, ['maybe', 'ready']>

c.maybe.maybe // not sure this is what you are going for here but it compiles..

游乐场链接

虽然上面的类型有效,但我不确定它是否真的有意义,也许您希望声明的字段T是特定类型(例如stringoranyboolean),那么您可以只使用映射类型Record。此外,我们通常将多个键作为联合而不是元组传递:

type WithStatic<P, T extends string> = {
  (props: P): void;
} & Record<T, string> // replace strign with whatever 

let c = ((p: {}) => 1) as any as WithStatic<{}, 'maybe' | 'ready'>

c.maybe = ""

游乐场链接

编辑

关于评论,您可以允许c.maybe.ready但不允许,c.maybe.maybe但您将需要使用联合而不是元组:

type WithStatic<P, T extends string> = {
  (props: P): void;
} & {
  [K in T]: Exclude<T, K> extends never? string : WithStatic<P, Exclude<T, K>>; // Added bottom 
}

let c = ((p: {}) => 1) as any as WithStatic<{}, 'maybe' | 'ready'>

c.maybe.maybe // error
c.ready.maybe = ""
c.maybe.ready = ""

游乐场链接


推荐阅读