Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Define type as a contravariant parent of another type

Consider type Foo as:

type Foo = {
  name: string,
  bar: {
    buzz: string,
    buzzy: number,
    buzzAldrin: boolean
  },
  active: boolean,
}

I want to define a type which represents a "part" of Foo. For example:

  • {name: string}
  • {name: string, active: boolean}
  • {bar: { buzz: string } }

Another way to see it is, a type that’s Foo‘s parent type when viewed as a contravariant parameter. So, naming that type CFoo, it would satisfy:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

((arg: CFoo) => any) extends ((arg: Foo) => any)

I can represent that relationship with a type that takes both Foo and CFoo and performs the assertion above:

type Contra<T, G> = ((a: G) => void) extends ((a: T) => void) ? G : never;

type Foo = {
    shape: string,
    name: 'circle',
    b: {
        d: string
    }
}

function test<T, G>(a: T, b: G extends Contra<T, G> ? G : never) {};

let a = {} as Foo;

test(a, {b: {d: 'asd'}}); // No error
test(a, {shape: 'test'}) // No error
test(a, {shape: 123}) // Error

Playground

But, what I really want to do is define a generic type that, when passed Foo produces a general contravariant parent type that I can use more succinctly.

type Contra<T> = // type definition
function test<T>(a: T, b: Contra<T>) {} // Should accept parameters just like the example above.

>Solution :

I think you over-engineered it:

function test<T, G extends T extends G ? unknown : T>(a: T, b: G) {};

You are also allowed to return something other than never. You get a nicer error message by returning T, and is not going to make the type invariant because it’s only evaluated when the first comparison fails.

Now, this is also an option:

function test<T extends G, G>(a: T, b: G) {};

Of course the error does not pop up in the same spot, but it does not always matter.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading