microsoft / microsoft/TypeScript
Generic constraints are "shallow", don't account for depth subtyping
Personne n'a encore pris cette issue.
- Langage dominant
- Go
- Étoiles
- 111k
- Forks
- 14.3k
- Merge moyen
- 2 j 4 h
- PR mergées (30 j)
- 132
Description
### 🔎 Search Terms
`ts1360 ts2322 generic fields` , `generic bound subtyping`, `generic constraint subtyping`, `could be instantiated with a different subtype of constraint`, `depth subtyping generics`, `parametric polymorphism depth subtyping`
### 🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the [documentation for generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) as of 5.9.2
### ⏯ Playground Link
[Playground link](https://www.typescriptlang.org/play/?ts=5.9.2#code/GYVwdgxgLglg9mABAZwIbAKYB4AqiMAeUGYAJsilAE4xgDmAfABQBQAkGKgLYYBclNegBpEAelGIAqmCoYANqmKlEUOIhwA6FgEp+eAN7tZUEFSSceYiQCE4UABb4qVOFWQjUFQgAcM0DKRaAL4sLKCQsAiI4GiYuPhEJOSI+ogAbqhyIHwCtHSIQczsFjnI1Hki4ogAyrByctEy8ooBKmo4ANoARBlZGF0Aulq66t292YMpRhgmZoglVogA6vYAnogwFA6biJlycADuAQD8LCEsVQCiBNzechiIcMCIwKgwWbIsMejYqeM5XQgii6BUQAB8UulMtl+F1SHA6CDCqw2F1gJt7F0dChFJt0RgKIDgeDEHCEV0gA)
### 💻 Code
Errors, as intended:
```ts
function safe(
name: string, // Unrelated to T.
): T {
return name // 'string' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. (2322) 👍
}
```
Does not error, unexpectedly:
```ts
function unsafe(
name: string,
): T["value"] {
return name // No error. Why is this allowed?
}
// Example uncaught error:
unsafe<{ value: "cat" } | { value: "dog" }>(
"fish"
) satisfies "cat" | "dog"
```
### 🙁 Actual behavior
When `T extends string`, TypeScript correctly identifies that an arbitrary other `string` cannot be safely assigned to `T`, because `T` could be instantiated with any subtype of string.
When `T extends { value: string }`, TypeScript incorrectly allows an arbitrary other `string` to be assigned to `T["value"]`, even though `T` could be instantiated with any subtype of `{ value: string }`, and the depth subtyping rule for objects implies that the type of `T["value"]` is also a subtype of `string`.
### 🙂 Expected behavior
- **Both examples should fail with the same error.** It should not be possible to return `name` in the function `unsafe`.
More generally, TypeScript should be consistent in applying subtyping rules to generic constraints `T extends U`. If `U` is a primitive (like `string` or `"A" | "B"`) and `T` is checked as if it could be instantiated with any subtype of `U`, then the same rule should apply when `U` is an object type.
- **If this is working as intended**, the [generics documentation](https://www.typescriptlang.org/docs/handbook/2/generics.html) should be updated to clarify that generic bounds are "shallow," and the correct approach is to use a second generic parameter.
Ideally this disclaimer could go under both the section on [Generic Constraints](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-constraints) (stipulating that only the top level parameter is treated as generic), as well as [Using Type Parameters in Generic Constraints](https://www.typescriptlang.org/docs/handbook/2/generics.html#using-type-parameters-in-generic-constraints) (to the effect of "note that this is the _only_ way to handle this pattern").
### Additional information about the issue
_No response_
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par le TypeScript Playground lié et comparez l’exemple générique de string avec l’exemple d’accès indexé en utilisant l’instanciation d’union montrée. Lisez les sections Generic Constraints et Using Type Parameters in Generic Constraints de la documentation sur les génériques. C’est terminé si les deux exemples reçoivent la même erreur appropriée ou si la documentation explique clairement le comportement de la contrainte superficielle et l’approche avec un deuxième paramètre.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- typescript
- Domaine
- compilers
- Type d'issue
- Bug
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100