Skip to content

Objects with a field of a conditional type that resolves to never are required #37104

Closed
@jeroenknoef

Description

@jeroenknoef

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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions