question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Inline Generics OR Expressing polymorphic relationships in interfaces with conditional types

See original GitHub issue

Search Terms

inferring generics in interfaces like in functions, inferring generics in interfaces

Suggestion

Functions in TypeScript can properly infer the type of generics without explicitly stating them.

Given the types

type Foo = "foo"
type Bar = "bar"
type FooBar = Foo | Bar;
type IfFooThenBar<T extends FooBar> = T extends Foo ? Bar :
  T extends Bar ? Foo : never;

The function

ifFooThenBar<T extends FooBar>(fooOrBar: T, barOrFoo: IfFooThenBar<T>): void

will: a) properly autosuggest available values, b) fail with if called with ifFooThenBar("foo", "foo")

I think it would be beneficial if interfaces would support this behavior, too. Given an interface

interface IIfFooThenBar<T extends FooBar> {
  fooOrBar: T
  barOrFoo: IfFooThenBar<T>
}

which would support inferring. you could implement it as

const fooConfig: IIfFooThenBar = {
  fooOrBar: "foo"  // this value would be checked
  barOrFoo: "foo" // and this would break
}

Use Cases

  • Interfaces where you don’t want propagate a Generic to you topmost implementer
  • Interfaces where you want to model a polymorphic relationship between keys

Examples

type Foo = "foo"
type Bar = "bar"
type FooBar = Foo | Bar;
type IfFooThenBar<T extends FooBar> = T extends Foo ? Bar :
  T extends Bar ? Foo : never;

// As inline type
interface IfFooThenBar {
  fooOrBar: T extends FooBar 
  barOrFoo: IfFooThenBar<T>
}

// As multiple inline types
interface IfFooThenBar {
  fooOrBar1: A extends FooBar 
  barOrFoo1: IfFooThenBar<A>
  fooOrBar2: B extends FooBar
  barOrFoo2 : IfFooThenBar<B>
}

// As inline type with "global" Generic
interface IfFooThenBar<A extends FooBar> {
  fooOrBar: T extends FooBar 
  barOrFoo : IfFooThenBar<T>
  globalFooOrBar: A
}

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.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
AnyhowStepcommented, May 26, 2019
type Concrete = Distribute<FooBar>;

//Becomes
type Concrete = IIfFooThenBar<Foo> | IIfFooThenBar<Bar>;

//Becomes
type Concrete = { fooOrBar : Foo, barOrFoo : Bar } | { fooOrBar : Bar, barOrFoo : Foo };

//Becomes
type Concrete = { fooOrBar : "foo", barOrFoo : "bar" } | { fooOrBar : "bar", barOrFoo : "foo" };
1reaction
RyanCavanaughcommented, May 17, 2019

This is too complex for something you can already do:


type Foo = "foo"
type Bar = "bar"
type FooBar = Foo | Bar;
type IfFooThenBar<T extends FooBar> = T extends Foo ? Bar :
	T extends Bar ? Foo : never;
  
interface IIfFooThenBar<T extends FooBar> {
  fooOrBar: T
  barOrFoo: IfFooThenBar<T>
}

type Distribute<T extends FooBar> = T extends T ? IIfFooThenBar<T> : never;
type Concrete = Distribute<FooBar>;

// OK
const fooConfig: Concrete = {
  fooOrBar: "foo",
  barOrFoo: "bar"
}

// Error
const barConfig: Concrete = {
  fooOrBar: "bar",  // this value would be checked
  barOrFoo: "bar" // and this would break
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - Conditional Types - TypeScript
Conditional types help describe the relation between the types of inputs and ... But the power of conditional types comes from using them...
Read more >
Higher Kinded Polymorphism / Generics on Generics #2212
So, in short: higher-kinded polymorphism is simply a more powerful form of generics. It is useful for precisely the same reason why generics ......
Read more >
Runtime Polymorphic Generic Programming—Mixing Objects ...
In object-oriented programming, libraries typically specify that the types supplied to the library must be derived from a common abstract base class, providing ......
Read more >
Can I preserve generics in conditional types? - Stack Overflow
Let's say I have a conditional type that changes the return type of a ... b: string) => undefined; interface IFoo { method1(a:...
Read more >
Inheritance and Polymorphism - Swagger
To help API consumers detect the object type, you can add the discriminator/propertyName keyword to model definitions. This keyword points to the property...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found