user3612643
user3612643

Reputation: 5772

Enforce intersection of generic types to extend a given type

Consider the following (non-compiling) TypeScript example:

type Optional<T> = { [K in keyof T]?: T[K] };

interface Foo {
    name: string;
    age: number;
}

function foo<A extends Optional<Foo>, B extends Optional<Foo>, A & B extends Foo>(a: A, b: B) : Foo {
    return {...a, ...b};
}

The idea of foo is to take two partial instances of Foo and enforce that their intersection (at least) extends Foo.

Is there a possible way to construct such a constraint?

If that was possible, is it possible to extend the solution to a flexible amount of argument? I.e. foo not only taking 2 arguments, but n arguments.

function foo<A extends Optional<Foo>[]>(a: ...A) : Foo {
    ...
}

Upvotes: 1

Views: 54

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250016

You can create a tuple type for a rest parameter that requires all that all properties of the last element in the tuple contains any properties that haven't already been specified:

interface Foo {
    name: string;
    lastName: string;
    age: number;
    id: number
}

function foo<A extends Partial<Foo>= {}, B extends Omit<Foo, keyof A> = Omit<Foo, keyof A>>(...a: [...A[], B]) : Foo {
    return Object.assign({}, ...a) as Foo;
}

let x = foo({ name: "" }, { lastName: "" }, { id: 0, age: 1})
let x2 = foo({ name: "" }) // error
let x4 = foo({ name: "" }, { lastName: "" }, { id: 0 }) // error
let x3 = foo() // error

Playground Link

Although the errors might be a bit hard to read

Upvotes: 2

Related Questions