首页 > 解决方案 > 获取复杂类型的补全

问题描述

我想为 /构造函数 argmyG传递Foo并获得完成(在 vscode 中),我可以让它工作,以便我获得或/的完成,但不是同时完成。Foo.getOBJKEY_OF_OBJFoo.getOBJKEY_OF_OBJ

interface G {
  [key: string]: string;
}
interface GE<T extends G> {
  [key: string]: T;
}

class Foo<T extends G, K extends GE<T>> {
  constructor(OBJ: K, KEY_OF_OBJ: keyof K) {}
  get(keyOfG: keyof T) {}
}

interface myG extends G {
  d: string;
  e: string;
}

const foo = new Foo<myG>(
  {
    a: {
      d: '',
      e: ''
    },
    c: {
      d: '',
      e: ''
    }
  },
  'c'
);
foo.get('');

编辑:必须Foo像这样声明new Foo<myG, {a: myG, c: myG}>也是可以接受的,像这样声明它的唯一问题是,它Foo.get不会自动完成,这是因为 ts 认为它​​是一个字符串的东西,如果我删除G,它可以工作,但我T想有key: stringValue对,我想我的问题已经解决了,除非有办法限制T只有字符串值。

标签: typescript

解决方案


我将假设您可以Foo通过手动指定类型参数TK泛型类型参数来构造实例:

const foo = new Foo<myG, { a: myG, c: myG }>(
    {
        a: { d: "", e: "" },
        c: { d: "", e: "" }
    }, "c"
);

所以你的问题是:当索引签名吸收并进入它时,我们如何在我们的 IDE 中为已知的文字键"d""e"of自动完成?也就是说,既然评估为 just ,我们如何让 IDE “记住” and ?myGstring"d""e""d" | "e" | stringstring"d""e"

关于这个有一个未解决的问题(Microsoft/TypeScript#33471),所以还没有简单而明显的答案。有哪些复杂和/或不明显的答案?这是一个。

首先,使用现有解决方案从具有索引签名的类型中获取已知的文字键:

type KnownKeys<T> = {
  [K in keyof T]: string extends K ? never : number extends K ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;

让我们验证它是否正确myG

type KnownKeysOfMyG = KnownKeys<myG>
// type KnownKeysOfMyG = "d" | "e"

看起来不错。现在,我们可以将get()签名更改Foo为 accept KnownKeys<T>

get(keyOfG: Extract<KnownKeys<T>, string>): void;

如果我们仍然想接受任意stringget(),这里的解决方法是为该接受添加第二个重载签名get()string

  get(keyOfG: Extract<KnownKeys<T>, string>): void;
  get(keyOfG: string): void;
  get(keyofG: string) {
     // impl
  }

它仍然接受所有string值:

foo.get(""); // okay
foo.get("d"); // okay
foo.get("e"); // okay
foo.get("fkjksjfksjfkds"); // okay

但是自动完成提示现在起作用了:

在此处输入图像描述

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读