Search code examples
typescriptpolymorphismrecordrow-polymorphism

Looking for a type that is polymorphic in record fields (static duck typing)


I am looking for a type that is polymorphic in record fields so that it accepts records containing more fields with the constrain that all involved records coincide in these extra fields:

type foo = { first: string, last: string };

const o = { first: "Foo", last: "Oof", age: 30 };
const p = { first: "Bar", last: "Rab", age: 45 };
const q = { first: "Baz", last: "Zab", gender: "m" };

const main = (o: foo) => (p: foo) => o.first + o.last

// goal

main(o)(p); // type checks
main(o)(q); // type error

Playground

Is this possible in TS?


Solution

  • You can achieve this by adding generic parameter.

    const main = <T extends foo>(o: T) => (p: T) => o.first + o.last
    
    main(o)(p); // allowed
    main(o)(q); // Property 'age' is missing in type '{ first: string; last: string; gender: string; }'
    

    Playground

    This works because generic type is inferred from first argument (o) and resolved to

    { first: string, last: string, age: number }

    Now second parameter (p) type should be assignable to the above.