Home > Mobile >  How to tell typescript the required type of a keyof
How to tell typescript the required type of a keyof

Time:11-05

How do I let the following code know that u is a string?

I am currently getting

Argument of type 'string | number | symbol' is not assignable to parameter of type 'string'

interface MyDef   {
    a: "a",
}

export class Router<t>{

    public generate<u extends keyof t>(path: u) {
        this.test(path)
    }

    public test(s: string) {
        console.log(s);
    }

}

const x = new Router<MyDef>();
// "a" is defined in MyDef - should work
x.generate("a");

// should not compile
x.generate("not-in-mydef");

Things I have tried

interface RouteSet {
    [k: string]: string;
}
// …

export class Router<t extends RouteSet>{
export class Router<t extends Record<string,string>>{
export class Router<t extends {[key: string]: string}>{

I can't seem to find a way to let TypeScript know I only ever want u to be a string.

I can this.test(path as any as string) to quiet the compiler, but that's far from ideal.

CodePudding user response:

If you intersect keyof t with string, you'll get only the keys of t that are strings:

class Router<t> {
    public generate<u extends keyof t & string>(path: u) {
        this.test(path)
    }

    public test(s: string) {
        console.log(s);
    }
}

See some examples in the playground below:

Playground

CodePudding user response:

Keys of a type can be strings, numbers or symbols. You have 2 options:

Option 1: Take any key on test function

class Router<T>{

    public generate(path: keyof T) {
        this.test(path)
    }

    public test(s: keyof T) {
        console.log(s);
    }

}

Option 2: restrict allowed keys to strings

class Router1<T>{

    public generate(path: keyof T & string) {
        this.test(path)
    }

    public test(s: string) {
        console.log(s);
    }

}

Note: the generic type is not necessary - I removed it.

  • Related