Skip to content

T extends unknown is observably-different from an unconstrained T #61242

Closed as not planned
@mkantor

Description

@mkantor

🔎 Search Terms

"extends unknown" "type parameter" "generic" "conditional type" "keyof" "string" "assignable"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about type parameter constraints

⏯ Playground Link

https://www.typescriptlang.org/play/?jsx=0#code/C4TwDgpgBAogHgQwLZgDYQDwBUB8UC8UWUEcwEAdgCYDOUA3gL5QD8UA1hCAPYBmRUAFxQawAE4BLCgHMAULIDG3CqKgBXCuwrcA7hQDCy0WIRTgBKNhJlKtdZu16cACjjD4yNJlwBKYcalpAjw4eSUVc21DCJMzC2wXN1hEFHQEvxFxQOCoOCA

💻 Code

type Example<T> = T extends {} ? keyof T : string

const unknownConstraint = <T extends unknown>(x: Example<T>): string => x

const noConstraint = <T>(x: Example<T>): string => x
//                                                 ^
// Type 'string | number | symbol' is not assignable to type 'string'.
//   Type 'number' is not assignable to type 'string'.

🙁 Actual behavior

The T extends unknown version behaves differently from the unconstrained version.

🙂 Expected behavior

The two versions should have the same behavior, probably both being rejected since code like this is unsafe:

const key = Symbol()
const bad = unknownConstraint<{ [key]: unknown }>(key)
bad.toUpperCase() // boom

Additional information about the issue

I was asked about this and eventually narrowed down the behavior to the example above.

#61203 is also possibly related?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Not a DefectThis behavior is one of several equally-correct options

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions