是否可以像打字稿中那样使用'this'关键字声明类型?

时间:2020-05-29 10:29:40

标签: typescript

示例:

// ===== Declaration ===== //
class A {
  CONSTS_TYPE: { [key: string]: [any] }
  CONSTS: { [key in keyof this['CONSTS_TYPE']]: key }
  foo<T extends keyof this['CONSTS_TYPE'] | string>(
    type: T,
    callback: (...args: T extends keyof this['CONSTS_TYPE'] ? this['CONSTS_TYPE'][T] : any) => any
  ) { /** some implementation*/ }
}
class B extends A {
  CONSTS_TYPE: {
    aa: [number],
    bb: [string]
  }
  // Here is the problem
  // Type '{ aa: "aa"; bb: "bb"; }' is not assignable to type '{ [key in keyof this["CONSTS_TYPE"]]: key; }'.(2322)
  CONSTS: { [key in keyof this['CONSTS_TYPE']]: key } = {
    aa: 'aa',
    bb: 'bb'
  }
}

// ===== Call ===== //
const b = new B;
b.foo(b.CONSTS.aa, (arg) => {
  // so that i can know 'arg' is a 'number' type
  arg // number type
});

效果很好,但效果不是很好。

我知道'// @ ts-ignore'会很好地工作

但我认为可能还有其他解决方案

[Playground Link]

3 个答案:

答案 0 :(得分:1)

所以,我认为您的代码存在一些问题:

  • 您应尽量避免使用@ts-ignore
  • aa: 'aa',不是一个数字,应该会引发一个错误。并不是您实施它的方式
  • ...args: T中,T是一个数组,而不是您认为的一个参数
  • 为什么在...args中使用foo

以下是我认为对您有用的解决方法:

// ===== Declaration ===== //
type ValueOf<T> = T[keyof T];

abstract class A {
  abstract CONSTS: { [key: string]: any }

  foo<T extends ValueOf<this['CONSTS']>>(
    type: T,
    callback: (arg: T) => any
  ) { /** some implementation*/ }
}

class B extends A {
  CONSTS: {
    aa: number,
    bb: string
  } = {
    aa: 5,
    bb: 'bb'
  }
}

// ===== Call ===== //
const b = new B;
b.foo(b.CONSTS.bb, (arg) => {
  // so that i can know 'arg' is a 'string' type
  arg // string type
});

typescript playground

答案 1 :(得分:0)

您实际上不是在寻找通用类吗?

declare class Foo<T extends Record<string, [any]>> {
  CONST_TYPES: T;
  CONSTS: {
    [K in keyof T]: K
  }

  constructor(types: T);

  foo<U extends keyof T>(type: U, callback: (value: T[U]) => any): any;
}

const foo = new Foo({ aa: [42], bb: ['foo'] });

foo.foo(foo.CONSTS.bb, (arg) => {
  arg // [string]
})

答案 2 :(得分:0)

最后我找到了解决方法

// ===== Declaration ===== //
class A<T extends Record<string, [any?]>> {

    foo<U extends keyof T | string>(
        type: U,
        callback: (...args: U extends keyof T ? T[U] : any) => any
    ) { /** some implementation*/ }
}

type T_BConstsType = {
    aa: [number],
    bb: [string]
}

class B extends A<T_BConstsType> {

    CONSTS: { [key in keyof T_BConstsType]: key } = {
        aa: 'aa',
        bb: 'bb'
    }
}

// ===== Call ===== //
const b = new B;
b.foo(b.CONSTS.aa, (arg) => {
    // so that i can know 'arg' is a 'number' type
    arg // number type
});

Playground