microsoft / microsoft/TypeScript

Generic type narrowing for truthy check has inconsistent / incorrect behavior

Aperta
#59,717 6 commenti 1 reazione 1 assegnatario Vedi su GitHub

@ahejlsberg ci sta già lavorando.

Dal 30/8/2024.

Needs Investigation
Lingua principale
Go
Stelle
111k
Fork
14.4k
Merge medio
1g 19h
PR unite (30g)
117

Descrizione

🔎 Search Terms

generic truthy narrowing generic index

🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about narrowing truthy generic types

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.7.0-dev.20240821&ssl=29&ssc=2&pln=1&pc=1#code/MYewdgzgLgBATgU1HAJgLhgJSSVAeaOASzAHMAaGAVzAGswQB3MAPhgF4YBvAXwG4AsAChhAMxrAoRcDFEgQeACowEADygIwKCDEIlSMAD6yAhgBsICIzDBUzZlgAoAbuYyKAlN2ExfMIqIwLuZeXD5+Ea5mgkIREQD08QB6APzhcTAARiZwwWYeMRm+iMgoANpRALocMACshX48KhZWYbFFUelxialdPML9IkLiYJLSYLLyAEx5GHpk1qLmlta29qFdAUFRG+0ZUQ0ZPWl7cdm5O4dxJbjlVTX1fc0rbUUwnacJyScRg4NiEikMnOs10UGIZF2EUQUCocAmBwGQA

💻 Code
const record: Record<string, unknown> = {};

function foo<T extends string | false | null>(val: T) {
    if (val) {
        val;
        //^?
        bar(val);
        record[val] = 5;
    } else {
        val
        //^?
    }
}

function foo2(val: string | false | null) {
    if (val) {
        val;
        //^?
        bar(val);
        record[val] = 5;
    } else {
        val
        //^?
    }
}

function bar(val: string) {
    return val;
}
🙁 Actual behavior

Error on line 8, cannot use val to index object type with string key.
Val appears to be narrowed to NonNullable<T> yet I can use it as string when calling functions?
Note: foo2 does not use generics and has more expected bahavior.

🙂 Expected behavior

type Falsy = false | null | undefined | 0 | "";
(might remove 0 | "" from this because that gets into negated types... false seems like a common enough one to matter though)

On line 5 inside of the if check, I expect val to be narrowed to Exclude<T, Falsy> but instead, is incorrectly (imo) narrowed to NonNullable<T> which does not exclude false.

What is exceptionally strange, is that the type narrowing behavior seems to differ depending on how val is used. I can pass it to the function that takes a string parameter, but when I try to use it to index an object on line 8, I get an error.

Additional information about the issue

This issue was discussed in detail by others more experienced than me in this typescript discord thread:
https://discord.com/channels/508357248330760243/1275942751724372110

Invite to server if you aren't a member:
https://discord.com/invite/typescript

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.