0

Example:

// ===== 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
});

it works well, but not too well.

i know '// @ts-ignore' will work really well

but I think there may be other solutions

[Playground Link]

3 Answers 3

1

So, I think there are some problem going on with your code :

  • You should avoid using @ts-ignore as much as you can.
  • aa: 'aa', is not a number and should have raised you an error. It didn't cause of the way you have implemented it
  • in ...args: T, T is an array and not one parameter as you think
  • Why use ...args in foo ?

Here is what I think could be a soluce to you :

// ===== 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

Sign up to request clarification or add additional context in comments.

Comments

0

Isn't a generic class what you're actually looking for instead?

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]
})

Comments

0

finally I found a solution

// ===== 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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.