-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
For object type C, type parameter T and mapped type { [K in keyof T & C]: any }, keyof C isn't assignable to K #18538
Comments
I take it back; we do certain checks over mapped types and really you're not depending on the original type of Any time that you use a type parameter that's only used in an output position, that's usually something that we see as pretty fishy. Could you on elaborate what you're trying to write? |
@DanielRosenwasser Yes, of course. The example was just a simplification of the problem. My case is that I'm doing a react component decorator (HOC); that is a function with type: type withConfirmation<OProps> = (c: Component<OProps>) => Component<OProps & ConfirmationModalProps> So, it returns a new component that receives the original props (OProps) and new ones. The problem is when I implement the decorator, there I define a new React Component (the wrapper) that expects both properties; and try to define interface ConfirmationComponentProps {
title: string;
}
class ConfirmationComponent extends React.Component<ConfirmationComponentProps & OProps > {
static propTypes: {
title: PropTypes.string.;
}
....
} now, typings for react, define that type ValidationMap<T> = {[K in keyof T]?: Validator<T> }; where As you can see, is not that I'm trying to do something fishy myself. It's just a combination of what i believe two valid usecases. On one side, having a decorator that expands the properties you may pass to the component, on the other side trying to define the
Hope it helps clarifying the need! |
I think I just ran into this too. function f<K extends string>(
key: K,
recordPlain: Record<K, any>,
recordIntersection: Record<K, any> & {foo: string}
) {
// keyof recordPlain is K
recordPlain[key]; // okay
// keyof recordIntersection is just "foo"? Why not K | "foo"?
recordIntersection[key]; // error: Type 'K' cannot be used
// to index type 'Record<K, any> & { foo: string; }'.
} This makes type guards for |
Is this also the same issue with trying to use the new inferred function foo<T>(x: T) {
if ("a" in x) {
x.a // Property 'a' does not exist on type 'T'.
}
} Or is this something else? |
@mcortesi An even more simplified view of the problem is assignment of the string literal function propTypes<OProps extends {}, K extends keyof (OProps & ConfirmationComponentProps)>(
k: K, t: 'title'): K {
k = t
return k
}; Unfortunately, since var n: never = propTypes<{}, never>('title', null as never) // 'n' now has the value 'title'!
var a: 'a' = propTypes<{ a: number }, 'a'>('title', 'a') // 'a' now has the value 'title'! I'll see if I can think of a workaround. |
But in the original issue, it's |
Good point. But |
Hi! @sandersn thanks for the reply. I agree with @jcalz since the example use type Readonly<T> = {
readonly [P in keyof T]: T[P];
} implies all keys of It's probably a special case, as you mention. Nevertheless, it worths nothing that if I don't use the intersection types ( function propTypes2() : {[K in keyof (ConfirmationComponentProps)]?: any } {
return {
title: null,
};
}; An idea here, is that it might be related to the fact that, since OProps is unkwown by But it's kinda messy. Don't know if that helps! |
@jcalz regarding your It's a separate issue. The first question that I think needs to be resolved is what to do when you have concrete types: interface A { a }
interface B extends A { b }
function f(a: A) {
if ("b" in a) {
a // what is the type of a? A? A & { b } ? never?
}
}
declare let a: A
declare let b: B
f(a)
f(b) |
So should I file it separately or not bother? |
@jcalz Yes, it's a good feature request. Might be impossible, but we should at least have an issue for people to explore the design space. |
I have a scenario that I think is caused by this issue, I've simplified it to the following: interface A {
prop: string;
}
declare let partialA: Partial<A>;
declare let a: A;
if (partialA.prop !== undefined) {
/*
TS2322: Type 'Partial<A>' is not assignable to type 'A'.
Types of property 'prop' are incompatible.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'
*/
a = partialA;
a;
} |
Was this magically fixed somewhere? I can't reproduce the issue anymore. Playground link |
We've made a lot of changes to type parameters, and I believe intersections as well, in 4.3. This does indeed look fixed. @jcalz What were you doing reproducing 4-year-old bugs??? |
TypeScript Version: 2.5.2
Code
Expected behavior:
Compile with no errors.
Actual behavior:
Fails with:
{ title: null }
is not assignable to {[K in keyof (OProps & ConfirmationComponentProps)]?: any }`The problem disappears if I remove the intersection type
&
and just useConfirmationComponentProps
; or if I replace OProps with a concrete type like:The text was updated successfully, but these errors were encountered: