Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No genericity on properties of generic types #61108

Open
gggdomi opened this issue Feb 4, 2025 · 1 comment
Open

No genericity on properties of generic types #61108

gggdomi opened this issue Feb 4, 2025 · 1 comment

Comments

@gggdomi
Copy link

gggdomi commented Feb 4, 2025

🔎 Search Terms

generic properties, named generics, generics nested, generics indexed, keyed type template, reverse mapped types, generic bags

Related (but much larger) :
#54254
#51612
#55521
#53017

🕗 Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ entirely.

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/MYewdgzgLgBMAWBTYBrGBeGAeAKjRAHlImACYQzQBOAlmAOYB8AFAQFww4A0MAnhzgCUHAG4gapDIxgBvAL4AoBaEiwAZhmx5CxMhWp16PAKr4iJcpSi0GLdpx78Yx4TDESpshTB8B6AFT+3j4w-jCAoORwIFRUyFAANrz4MdEQHME+YQCCVPQArgC2JLAgGlC8AA6IMADkxjUwNBRgILAAhhAQNPRgbQBG8dVQIDAVbVRtRcRUMKUw5VW1ODUAdBmhIXUNTTAdXT39g-MjUEhRqhN0JWWV1TXLPH15sPcNoHnxkn3VdNBtYFAaG1iJIAO40U67GCkGhqNSIWIAyh5PoLapzFTUNpXWoGBg1db+XwZBDIFCsRyCGAKRTKcDQGD0TS4My6SwyGBqEAgDh4plyEysiwUDlcnlWGz8uwCRwcFyicSSdDSGTrAJBEIbQAy5DAWskqNEeKREBAKhDqt9DLqRgVotU9t1egMhvB-rs+iARIgVjAAOqIGqSeI0FDVCAgKbwK3B0NsQkwHL5IpIuZo2rGADaNTFNQAuttmq1dp1HYchiMxhMpgjZjdFvcszn82tNWFNpns9z840KA6Ds7jvMzpjrNiU3W7jhG12ao9nktpyA828QB8vj9VP9AcDEGCIfAoTC4QjisjUbda+csTianyCa3qQ+AMJ5GLFRI8UFIMDzW4AWlJVArQgFE-wqA0qioQETR4CEYHibkUAoGNqjwf5JFMcYwxoAoKkSRowHhN9JA6GAv2BIdECSHRhXjGhvU4TRRW5XlrCtOR8FgUxMGY8U+RgRRWyJEkkFQVgVjFRwJO5QQaQUIA

💻 Code

const check = <T extends string>(x: T, y: T): void => {}

const f = <T extends string, U extends string>(x: T, y: U): void => {
   /**
    * ✅ correctly errors: 
    * Argument of type 'U' is not assignable to parameter of type 'T'.
    *   'U' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'
    */
   check(x, y) 
}

const g = <T extends { foo: string }, U extends { foo: string }>(x: T, y: U): void => {
    /**
    * ❌ no error, despite being no more assignable than above. We'd like something like:
    * Argument of type 'U['foo']' is not assignable to parameter of type 'T['foo']'.
    *    'U['foo]' is assignable to the constraint of type 'T['foo]', but 'T['foo']' could be instantiated with a different subtype of constraint 'string'
    * 
    * Currently, when type-checking sub-properties, it looks like T and U are simply inferred as what they extends
    * ie. T = { foo: string } et U = { foo: string }
    **/
   check(x.foo, y.foo)
}

🙁 Actual behavior

The sub-property is no more assignable than it's parent. But we get no error.

🙂 Expected behavior

Some type error on the second check similar to the first one.
Something like:

The Argument of type 'U['foo']' is not assignable to parameter of type 'T['foo']'.
    'U['foo]' is assignable to the constraint of type 'T['foo]', but 'T['foo']' could be instantiated with a different subtype of constraint 'string'

Additional information about the issue

No response

@jcalz
Copy link
Contributor

jcalz commented Feb 4, 2025

#60406

It's intentional that if t is of generic type T extends {prop: U} that t.prop is widened to the constraint U. Indexing with specific non-generic keys just does that. You can always force the type to stay T["foo"] and U["foo"], but the unsettling thing is that TS sees that as mutually assignable:

const h = <T extends { foo: string }, U extends { foo: string }>(x: T["foo"], y: U["foo"]): void => {
   check(x, y); // also allowed
   check(y, x); // also allowed
}

which is a design limitation as per #54160.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants