Comments (8)
I can see that but it also means that the P[K] & {} being assignable to S[K] (something that is allowed today) is already speculative too, right?
Well, it's allowed only because of the oddity of Record<string, any>
constraints (see my comment).
from typescript.
Simpler repro:
function f1<T extends Record<string, any>, K extends keyof T>(x: T[K] | undefined) {
if (x === undefined) return;
x; // T[K] & ({} | null)
if (x === undefined) return;
x; // T[K] & {}
}
from typescript.
In addition to the odd narrowing behavior demonstrated by the OP and the simplified repro above, we also have inconsistencies in type relationships involving intersections that strip undefined
, null
, or both:
function f2<T, K extends keyof T>(t: T[K], p1: Partial<T>[K] & {}, p2: Partial<T>[K] & ({} | null)) {
t = p1;
t = p2; // Unexpected error
}
The issue here is missing normalization of intersections in certain cases. Specifically, we only normalize intersections with {}
, not intersections with null
or undefined
.
from typescript.
@ahejlsberg that feels like an answer to this comment, right? I mean, this extra observed problem would fix what has been described there.
Do you plan to work on fixing this? Or should I try to extend my PR with a fix for this?
from typescript.
Furthermore, using Record<string, any>
as a constraint exhibits some odd behavior:
function f3<T, P extends Record<string, any>>(t: T[keyof T], p1: P[keyof P], p2: P[keyof P] & {}) {
t = p1; // Error as expected
t = p2; // Missing error
}
function f4<T, P extends Record<string, unknown>>(t: T[keyof T], p1: P[keyof P], p2: P[keyof P] & {}) {
t = p1; // Error as expected
t = p2; // Error as expected
}
This has to do with the constraint of P[keyof P]
being any
which effectively circumvents type checking in some cases. In general, it seems suspicious for any instantiable type to have a constraint of any
, and we do indeed ignore such constraints in places. Just not everywhere.
from typescript.
@ahejlsberg that feels like an answer to #57692 (comment), right? I mean, this extra observed problem would fix what has been described there.
Given type parameters S
and K extends keyof S
, I would expect Partial<S>[K] & ({} | null)
to be assignable to S[K]
. However, when P extends Partial<S>
, I think expecting P[K] & ({} | null)
to be assignable to S[K]
is getting speculative.
Do you plan to work on fixing this? Or should I try to extend my PR with a fix for this?
I will be putting up a PR that fixes the issues demonstrated by f1
and f2
above.
from typescript.
However, when
P extends Partial<S>
, I think expectingP[K] & ({} | null)
to be assignable toS[K]
is getting speculative.
I can see that but it also means that the P[K] & {}
being assignable to S[K]
(something that is allowed today) is already speculative too, right?
from typescript.
It has been called an oddity but I'm not sure if I should interpret this as "odd but working as intended" or "odd and it could be fixed" 😅 In general, I interpret your comments about this here as the latter but I'm not 100% sure.
from typescript.
Related Issues (20)
- TS7018 error without file and line number HOT 6
- JSDoc tags get lost when inheriting from a grandparent class
- Smarter String includes/endsWith/startsWith using template literal type predicates HOT 3
- Typed key accessor fails to infer type when used with generic HOT 2
- Upstream file not correctly recognized as output of other project when using path mappings HOT 9
- [nightly][regression] Wrong generic parameter inferred for constructed class instance HOT 1
- [nightly][regression] Some emitted imports are syntactically invalid HOT 5
- Array of numbers wrong sort HOT 9
- Mistake in README file
- Inconsistent Behavior with Equality Check Using `Pick<Readonly<T>, K>` in Mapped Type HOT 2
- Improve Omit field type check HOT 1
- Class parameter property with initializer before required property emits non-nullable parameter for declaration emit
- TypeScript emits incorrect type for setters in JSDoc
- Function returning `never` in branch doesn't narrow type if it's not explicitly annotated HOT 3
- Type Intersection incorrect for optional parameters in functions with `exactOptionalPropertyTypes: true`. `undefined` type is flip based off Intersection types
- Inconsistent tsc behavior on TS 5.4 HOT 3
- VSCode TypeScript extension writes tracing to the wrong directory on Mac OS HOT 1
- computed property name in an interface error when using `[]` already HOT 3
- Proposal: Type-side `instanceof` keyword and functionality HOT 8
- tsserver.js CPU/Memory Spike HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typescript.