ken
ken

Reputation: 9013

How to get a "Type Mapping" function typed correctly

I have a type which is for a function which maps from one type I to another type O (aka, input and output types). It looks like this currently:

export interface IFunctionalMapping<I, O, K extends keyof O> {
  [prop: Extract<O[K], string>]: (input: keyof I, obj?: I) => K;
}

With the idea that one would use it like so:

export interface IFunctionalMapping<I, O, K extends keyof O> {
  [prop: Extract<K, string>]: (input: I) => O[K];
}

export interface IInput {
  firstName: string;
  lastName: string;
}

export interface IOutput {
  fullName: string;
}

const mapping: IFunctionalMapping<IInput, IOutput> = {
  fullName: (i) => `${i.firstName} ${i.lastName}`
}

The goal would be that the properties for mapping would be constrained to valid properties of IOutput and that the type exported by the function would be of the type of IOutput's property type.

It seems I'm not doing things 100% right as first off all I get an error on the IFunctionalMapping interface:

enter image description here

Which I would have thought would be avoided by my use of the Extract syntax.

Second, my attempt to type mapping to IFunctionalMapping complains that it needs 3 types ... I would have though that K extends keyof O would not need to be passed in as it's implied by the definition of O. But clearly I must be wrong about that too.

enter image description here

Upvotes: 1

Views: 35

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249646

If you need to use a mapped type to map the types of IOutput :

export type IFunctionalMapping<I, O> = {
    [K in keyof O]/*?*/: (input: I) => O[K]; // If you don't want all properties to be required, uncomment the ?
}

export interface IInput {
    firstName: string;
    lastName: string;
}

export interface IOutput {
    fullName: string;
}

const mapping: IFunctionalMapping<IInput, IOutput> = {
    fullName: (i) => `${i.firstName} ${i.lastName}`
}

Upvotes: 2

Related Questions