打字稿:带有类​​验证的属性键

时间:2019-04-01 04:41:38

标签: typescript generics

需要通用提示。 想要将Child类属性键用作Super.method的参数 并且Child[key]应该是Sub类。

class Parent {
  method<T extends keyof this>(keys: T[]){
  }
}

class Child extends Parent {
  a = new Sub;
  b = new Sub;
  c = new Sub;
  d = new Nope;
  e = new Nope;
}

child = new Child;
child.method(['a', 'b', 'c']);

仅显示所有属性键。 接下来不知道用于过滤类的内容。

如下所示的辅助显示键。

  • 'a'
  • 'b'
  • 'c'
  • d'
  • 'e'

想要更改如下:

  • 'a'
  • 'b'
  • 'c'

2 个答案:

答案 0 :(得分:1)

是的,您可以自动执行此操作。

注意:您没有提供SubNope的类型定义,因此我将添加一些定义。在示例中,这样做实际上很重要,因为TypeScript类型系统基于stucture,而不是names。这意味着名称SubNope是唯一的事实并不意味着编译器将它们视为不同的类型。如果它们具有相同的属性,则编译器将它们视为相同的类型,因此将Sub类型的类属性与Nope类型的类属性进行区分的任务将是不可能的。因此,让我们这样做:

// important that Sub and Nope are stucturally distinct types
// so the compiler can tell the difference
class Sub {
  sub!: string;
}
class Nope {
  nope!: string;
}

现在Sub有一个"sub"键,而Nope有一个"nope"键,编译器将能够区分它们。

您可以创建以下类型别名KeysMatching<T, V>,该别名将产生T的所有键,其中该键的属性可分配为类型V

type KeysMatching<T, V> = {[K in keyof T]: T[K] extends V ? K : never}[keyof T];

它使用mappedconditional类型。现在,可以通过将keyof this替换为KeysMatching<this, Sub>来按所需方式键入方法:

class Parent {
  method<T extends KeysMatching<this, Sub>>(keys: T[]){
  }
}

class Child extends Parent {
  a = new Sub;
  b = new Sub;
  c = new Sub;
  d = new Nope;
  e = new Nope;
}

让我们确保它能起作用:

const child = new Child;
child.method(['a', 'b', 'c']); // okay
child.method(['d','e']); // error!

对我很好。这是Playground link to this code。希望能有所帮助;祝你好运!

答案 1 :(得分:0)

您可以将de从有效选择中删除,方法是将其从班级中删除,或者将其设为private。这样,自动完成列表将仅具有'a', 'b', 'c', 'method'的功能-请注意该方法存在,因为它是从基类继承的。

您也可以通过删除除您指定的名称之外的所有名称来进行更多控制,尽管这将很麻烦:

class Parent {
    protected baseMethod<T extends keyof this>(keys: T[]){
    }
}

class Child extends Parent {
    a = new Sub();
    b = new Sub();
    c = new Sub();
    d = new Nope();
    e = new Nope();

    method<T extends keyof this & 'a' | 'b' | 'c'>(keys: T[]) {
        this.baseMethod(keys);
    }
}

在上面的示例中,尝试指定de将导致警告。