Typescript: Objects with a field of a conditional type that resolves to never are required

Created on 28 Feb 2020  ·  4Comments  ·  Source: microsoft/TypeScript

Search Terms


never conditional type undefined

Suggestion

With an interface like this:

interface A<T> {
    n: T extends number ? number : never
    s: T extends string ? string : never
}

this doesn't compile:

const a: A<string> = {
    s: "blah"
}

The type checker still requires the n field, even though it should be never. In other words, as it stands, you can't create an object of this type (as far as I know). My suggestion is to take care of this case and allow this construct.

I thought this worked in some earlier (not too recent) version of TypeScript. I remember that even VS code knew that it shouldn't suggest n in this example. It now does suggest the option. In actual code where we previously used something like this, the fields are optional, which is still working. In the above case, I need the field to be required.

Since I'm apparently not sure if it's a regression or intended behaviour, I'm posting this as a feature request.

Use Cases

We would use this feature for objects like the above where some fields are required only if some type parameter has some type. That would in our case usually be objects of a more declarative nature, such as configs or options objects (in case a function would otherwise have too many arguments).

The above case is solvable, as suggested on the TS site (code copied from there):

type BoxedValue<T> = { value: T };
type BoxedArray<T> = { array: T[] };
type Boxed<T> = T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;

but for a larger number of fields and/or type parameters, this explodes and leads to more and more code duplication.

Another solution would be to create multiple interfaces and let them extend each other. That feels more like the Java way of doing things.

Maybe Pick offers another way out, but that would still require additional boiler plate which in my opinion shouldn't be necessary.

Examples

This is part of our project that currently doesn't work:

export interface ModuleConfig<T, M extends Mutability> {
    readonly path: Path
    readonly dataSource?: DataSource<T>
    readonly rules: M extends Mutability.ENABLED ? ObjectRules<T> : never
}

The rules field is always required at the moment.

Checklist

My suggestion meets these guidelines:

  • [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • [x] This feature would agree with the rest of TypeScript's Design Goals.
Working as Intended

Most helpful comment

You can easily apply this to your own types already if you want to:

Playground

All 4 comments

Some might use the never type in a prop as signaling that the entire type cannot be constructed. And, in general, that's what never means.

In particular, I would be pretty upset because you'd break my CompileError<> type =P

https://github.com/microsoft/TypeScript/issues/23689#issuecomment-512114782


You might be interested in this, https://github.com/microsoft/TypeScript/issues/13195

You can easily apply this to your own types already if you want to:

Playground

As @AnyhowStep mentioned, an object with a never property can't be constructed. @nmain 's suggestion would be the correct way to approach this -- you could also use a different signaling type if you wanted.

Thanks for your suggestion @nmain, I'll give that a try.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wmaurer picture wmaurer  ·  3Comments

bgrieder picture bgrieder  ·  3Comments

weswigham picture weswigham  ·  3Comments

manekinekko picture manekinekko  ·  3Comments

fwanicka picture fwanicka  ·  3Comments