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.

Type inference regression in TypeScript v4.5

See original GitHub issue

Bug Report

Sorry for the vague title, wasn’t sure how to name it otherwise

🔎 Search Terms

  • type inference 4.5
  • PickKeysByValue

🕗 Version & Regression Information

  • This changed between versions 4.4.4 and 4.5.4

⏯ Playground Link

💻 Code

type PickKeysByValue<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];

export type PickProperties<T, P> = Pick<T, PickKeysByValue<T, P>>;

const obj = {
  a: 'a',
  b: 15,
};

function acceptOnlyString(str: string): void {}

function fn<T extends object, K extends PickKeysByValue<T, string>>(item: T, key: K) {
  acceptOnlyString(item[key]); // Argument of type 'T[K]' is not assignable to parameter of type 'string'.
}

🙁 Actual behavior

Line acceptOnlyString(item[key]); throws an Error Argument of type 'T[K]' is not assignable to parameter of type 'string'.

🙂 Expected behavior

The line should pass - key is limited to only keys for which item[key] is string

Issue Analytics

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

github_iconTop GitHub Comments

5reactions
RyanCavanaughcommented, Feb 18, 2022

This code only worked in 4.4 because the type wasn’t being checked at all:

type PickKeysByValue<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];

export type PickProperties<T, P> = Pick<T, PickKeysByValue<T, P>>;

const obj = {
  a: 'a',
  b: 15,
};

function acceptOnlyString(str: string): void {}
function acceptOnlyNumber(num: number): void {}

function fn<T extends object, K extends PickKeysByValue<T, string>>(item: T, key: K) {
  // OK
  acceptOnlyString(item[key]);
  // Also OK!
  acceptOnlyNumber(item[key]);
}

We don’t yet have logic that can figure out that K extends PickKeysByValue means item[key] must be a subtype of string. I’m going to make a follow-up proposal for this since it’s an oft-requested feature

1reaction
kaya3commented, Mar 5, 2022

A workaround is to declare the type of item as T & Record<K, string>. This fixes the type error in the function, and usually won’t cause an error at the call-site.

function fn<T extends object, K extends PickKeysByValue<T, string>>(item: T & Record<K, string>, key: K) {
  acceptOnlyString(item[key]);
}

Playground Link

Read more comments on GitHub >

github_iconTop Results From Across the Web

Announcing TypeScript 4.5 - Microsoft Developer Blogs
TypeScript 4.5 now can narrow values that have template string types, and also recognizes template string types as discriminants. As an example ...
Read more >
Documentation - Type Inference - TypeScript
This kind of inference takes place when initializing variables and members, setting parameter default values, and determining function return types. In most ...
Read more >
Type Inference for Static Compilation ... - Jean-Baptiste Jeannin
In this paper, we report on a type inference algorithm for ... b : 4 o3 a : 5 previous values of a...
Read more >
How do I tell Typescript that I expect exactly 2 elements from ...
DigitRange : never : never type Result = ToInt<1 | 2 | 3 | 4 | 5, '2'> // 2 ... type Inference<...
Read more >
Type Inference for Static Compilation of JavaScript
In this paper, we report on a type inference algorithm for ... b : 4 o3 a : 5 previous values of a...
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