简体   繁体   中英

Is there a way to narrow the type of an argument based on another argument to a function in Typescript?

I'm trying to create a mini DSL for some filter type operations and writing some helper methods for it.

Say I have function

const equals = (left, right) => {}

This functions needs to be typed such that the left value is a field on an object, and right is a value of the type of that object.

If I do const equals = <T> (left: keyof T, right: T[keyof T]) => {} , I get close but right is narrowed down to the types available on T rather than just the type of left .

The desired behaviour is achievable with this:

const equals = <T, F extends keyof T>(left: F, right: T[F])

But this requires two generic parameters which breaks my type inference chain for the code around this function. Ideally I want to type the second parameter based on the first parameter. Is this possible?

Thanks

You are probably looking for something around the following lines. The solution is to move some of the type validation logic to smart constructors.

// model
type PickPropertiesOfType<T, A> = Pick<
  A,
  {
    [K in keyof A]: A[K] extends T ? K : never;
  }[keyof A]
>;

export type Filter<A> =
  | { kind: "Equals"; field: string & keyof A; value: A[string & keyof A] }
  | { kind: "EqualsField"; field: string & keyof A; value: string & keyof A };

export const equalsOtherField = <A, K extends string & keyof PickPropertiesOfType<A[K], A>>(
  field: string & K,
  value: string & keyof PickPropertiesOfType<A[K], A>
): Filter<A> => ({
  kind: "EqualsField",
  field,
  value: value,
});

export const equals = <A, K extends string & keyof A>(field: string & K, value: A[K]): Filter<A> => ({
  kind: "Equals",
  field,
  value: value,
});

// example
type ExampleEntity = {
    author: string;
    publisher: string;
    year: number;
}

const exampleEntity: ExampleEntity = {
    author: "Foo",
    publisher: "Foobar",
    year: 2000
}

const filterArr: Filter<ExampleEntity>[] = [
  equals("author", "Bar"),
  equalsOtherField("author", "publisher"),
];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM