dagda1
dagda1

Reputation: 28780

specify argument has to have keyof property

I have the following playground with the following code:

export interface Coordinate {
  x: number;
  y: number;
}

export interface Line {
  source: Coordinate;
  target: Coordinate;
}

export type Selector<T, K extends keyof T> = (d: { [key: string]: K }) => typeof d[K];

export interface LinkVerticalLineProps {
  x: Selector<Coordinate, 'x'>;
  y: Selector<Coordinate, 'y'>;
}

class Foo implements LinkVerticalLineProps{
    originX: number;
    originY: number;

    constructor({ x, y }: Coordinate) {
        this.originX = x;
        this.originY = y;
    }

    x(other: Coordinate) {
        return other.x;
    }

    y(other: Coordinate) {
        return other.x;
    }
}

But typescript is not happy.

How I can I satisfy the compiler that the x function must take an object that has x for a property and returns typeof d[K]

Upvotes: 1

Views: 19

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249536

You can use Pick to pick out just one property of a type :

export interface Coordinate {
     x: number;
     y: number;
}

// Use Pick to pick out just one property 
export type Selector<T, K extends keyof T> = (d: Pick<T,K>) => T[K]; // you can also use typeof d[K] but it's the same as T[K] but longer 

//Does the same thing but less repeating the property names 
export type LinkVerticalLineProps = {
    [P in keyof Coordinate]: Selector<Coordinate,P>
}



class Foo implements LinkVerticalLineProps{
    originX: number;
    originY: number;

    constructor({ x, y }: Coordinate) {
        this.originX = x;
        this.originY = y;
    }

    // We must repeat the Pick, ts will not infer class member argument types 
    x(other: Pick<Coordinate, 'x'>) {
        return other.x;
    }

    y(other: Pick<Coordinate, 'y'>) {
        return other.y;
    }
}

Upvotes: 1

Related Questions