microsoft / microsoft/TypeScript

Allow composite values to be used in type predicates

Open
#43,640 2 comments 0 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

Allow composite values to be used in type predicates

🔍 Search Terms

Is, composite type, complex type, composite value, complex value, type predicate, type guard

✅ Viability 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, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

⭐ Suggestion

Type predicates allow you to define functions that can tell the TypeScript compiler if a parameter is of a certain type.
I suggest that this be extended to allow type predicates to narrow the type of composite objects involving parameters.
That is, the left-hand-side of is types should be allowed to include object literals.

📃 Example

Say you have a type that involves a subset of another type:

type MyType = {property1: "static text", property2: "Hello" | "World"};

A type predicate for this would always require passing in the property1 property, even though it’s unnecessary.
Now, you can create a type predicate that only takes the value of property2, but still gurantees the result type:

function foo(text: string): {property1: "static text", property2: text} is MyType {
    return ["Hello", "World"].includes(text);
};

I’ve run into the problem of being unable to do this while developing my website.
I had a tagged union:

type A = {t: "A", value: "X" | "Y"};
type B = {t: "B", value: string};
type U = A | B;

And I wanted to get a value of type A from user input, but default back to a B type if the value wasn’t
To do this, I hoped to be able to do this:

function zit(x: string): {t: "A", value: x} is A {
    return ["X", "Y"].includes(x);
};
function gob(x: string): U {
    return zit(x) ? {t: "A", value: x} : {t: "B", value: x};
};

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

No files, tests, or entry points are named. Start by reviewing the issue’s type-predicate examples and the compiler’s existing type-guard behavior; the change would be complete when composite object types are accepted in predicates and the shown narrowing scenarios work without changing emitted JavaScript.

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
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.