microsoft / microsoft/TypeScript

Allow classes to implement unions of object types

Open
#62,630 17 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Awaiting More Feedback Suggestion
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

🔍 Search Terms

class extends union type

✅ Viability Checklist
⭐ Suggestion

Allow classes to extend unions of object types when the types in the union have the same set of properties.

The goal is to allow type-narrowing on class instances by checking a discriminant field.

📃 Motivating Example

I often have classes that represent data that can be in one of several states, and whose fields depend on that state.

An example is an object that is imported into a database with a long task. The app will write a record to the database to indication that it's currently being imported, and locking it from other writers.

We might model that with two interfaces: ImportingFoo, and ImportedFoo, discriminated by a status field:

type FooStates = ImportingFoo | ImportedFoo;

interface ImportingFoo {
  status: 'importing';
  value: undefined;
}

interface ImportedFoo  {
  status: 'imported';
  value: string;
}

We want our class to implement this type to indicate what type value can be depending on the type of status:

class Foo implements FooStates {
  status: 'importing' | 'imported' = 'importing';
  value: undefined | string;
}

This currently gives a "A class can only implement an object type or intersection of object types with statically known members.(2422)" error.

If we could do that, we could use narrowing for the instance:

const getValue = (foo: Foo): string => {
  if (foo.status === 'imported') {
    return foo.value; // OK, because foo narrowed to a ImportedFoo
  }
  throw new Error('Invalid state');
}
💻 Use Cases
  1. What do you want to use this for?
  • Classes that act as discriminated unions
  1. What shortcomings exist with current approaches?
  • The class can't explicitly implement the union, narrowing doesn't automatically work
  1. What workarounds are you using in the meantime?
  • Cast the instance to an intersection of the class and interface: foo as Foo & ImportedFoo, but this is error prone as the cast will succeed in cases where it shouldn't.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the class implements validation that produces diagnostic 2422, then inspect how discriminated-union narrowing works for class instances. Compare the proposed FooStates and Foo examples, and identify the compiler tests covering class implementation and narrowing. Done means valid union implementations are accepted and the shown foo.status check narrows foo.value correctly without changing JavaScript output.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.