Home > Mobile >  Typescript: Get correct value type from object by key generic
Typescript: Get correct value type from object by key generic

Time:07-20

in the example I want to write an simple query builder where all types of an entity are correctly casted. For example when im filtering with equalsTo for name I only want to allow strings as values, same for age there should only be numbers allow. Now value can be any value of Dogs and thats not what I want. Can somebody help me is this possible?

class Dogs {
    name!: string;
    age!: number;
    alive!: boolean;
}
interface QueryBuilder<O extends object, F extends keyof O = keyof O> {
    equalsTo: (fieldName: F, value: O[F]) => boolean;
}
const queryBuilder = <O extends object>(): QueryBuilder<O> => ({
    equalsTo: (fieldName, value) => true 
})
const qb = queryBuilder<Dogs>();
qb.equalsTo("name", 1); // Should throw an error that only string is allowed as value
qb.equalsTo("age", "Rex"); // Should throw an error that only number is allowed as value

CodePudding user response:

Your interface definition:

interface QueryBuilder<O extends object, F extends keyof O = keyof O> {
    equalsTo: (fieldName: F, value: O[F]) => boolean;
}

is allowing the second parameter of equalsTo to be string | number | boolean because TypeScript can't narrow the type any further at the class level.

However - if you type-annotate the function itself:

interface QueryBuilder<O extends object> {
    equalsTo: <F extends keyof O = keyof O>(fieldName: F, value: O[F]) => boolean;
}

... you get the behaviour you're looking for:

qb.equalsTo("name", 1); // Argument of type 'number' is not assignable to parameter of type 'string'.(2345)

qb.equalsTo("age", "Rex"); // Argument of type 'string' is not assignable to parameter of type 'number'.(2345)


TypeScript playground

  • Related