let x: Partial<any>
let y: number = x // Type 'Partial<any>' is not assignable to type 'number'.
let z: string = x // Type 'Partial<any>' is not assignable to type 'string'.
Partial<any> should be considered as any and can be assigned to other types.
Do you have a real world use case for this?
It appears to be intentional because Partial<any> is the only one that actually generates a general indexer:
type PartialString = Partial<string>; // string
type PartialNumber = Partial<number>; // number
type PartialObject = Partial<object>; // object
type PartialWeakObject = Partial<{}>; // {}
type PartialAny = Partial<any>; // { [x: string]: any; }
Yes I do, as in the linked PR:
https://github.com/unional/assertron/blob/master/src/satisfy.ts#L13
This issue is breaking this case:
https://github.com/unional/assertron/blob/master/src/satisfy.spec.ts#L118
By the way, type number & 123 should be treated as 123, string & 'abc' should be 'abc'
Partial and Record are mapped types, and these assume a transformation on the members of an object type.. there is a special treatment for primitives as noted by @kitsonk , since mapping primitive properties is rather meaningless.
Now, any can be thought of as an infinite union of all possible types, that include both primitive and object types.. a mapping operation on that infinite union would ignore primitives (number, string, etc..) and would only operate on the object types. the result of that transformation is guaranteed to always be an object type; the names of the properties is the infinite set of all possible property names (string) and their types are all possible types (any) hence the result is `{ [x: string]: any }.
I think there is something to be said on the use of anyas an argument to Partial.. either you need a generic type parameter threaded through to be able to do the transformation correctly, or it should be explicitly specified as any and avoid the confusion.
Please see https://github.com/Microsoft/TypeScript/pull/19185 for more details about the change.
Duplicate of https://github.com/Microsoft/TypeScript/issues/19624
I think #19185 may be over-solving the issue in #19152.
I can understand that { [P in any]: T } and { [P in keyof any]: T } should yield { [x: string]: T}
But that doesn't mean Partial<any> or ReadOnly<any> should resolve to { [x: string]: any } and { readonly [x: string]: any }
In #19152, the problem is the indexer, not the property type, that have the problem.
Also, Partial<any> and ReadyOnly<any> has a semantic meaning. In these circumstances, I think your statement "any can be thought of as an infinite union of all possible types, that include both primitive and object types" would be a more perceivable take.
I understand that Partial and Recordare mapped types, but as they need special treatment for primitives, I think they also need special treatment for any. 馃尫
a use-case equivalent to this:
function consumer(p:{foo:string}){}
const obj :Partial<any> = {foo:'bar'};
consumer(obj); // TS2345:Argument of type 'Partial<any>' is not assignable to parameter of type '{ foo: string; }'. Property 'foo' is missing in type 'Partial<any>'.
currently blocks wix/wix-react-tools#188
@amir-arad any change here wouldn't solve the issue with your code. It is unrelated. For example the following is an error:
function consumer(p:{foo:string}){}
const obj: Partial<{ foo: string }> = {foo:'bar'};
consumer(obj);
You have a situation where the key you require is optional on the source type. That won't ever work.
from the Documentation site :
The any type is a powerful way to work with existing JavaScript, allowing you to gradually opt-in and opt-out of type-checking during compilation.
I expect Partial to be consistent in that matter with other type expressions, such as unions and intersections, where any plays that special role:
function consumer(p:{foo:string}){}
const obj: (any & {foo:null}) | {foo:number} = {foo:'bar'};
consumer(obj); // this works fine
I can understand that { [P in any]: T } and { [P in keyof any]: T } should yield { [x: string]: T}
To nail this a bit more, I can see the rationale for #19185
type X<T, R> = {
[P in keyof T]?: R;
};
let x: X<{ a: number, b: string }, { foo: number }> = { a: { foo: 1 }, b: { foo: 2 } }
// y: { [P: string]: { foo: number } }
let y: X<any, { foo: number }> = { c: { foo: number } }
// z: { a: any, b: any }
let z: X<{ a: number, b: string }, any> = { a: 'a', b: 1 }
But Partial<T>, ReadOnly<T>, or some others should behave more than mapped type, as they have special cases for primitives.
But Partial
, ReadOnly , or some others should behave more than mapped type, as they have special cases for primitives.
all mapped types have the same behavior for primitives..
I expect
Partialto be consistent in that matter with other type expressions, such as unions and intersections, whereanyplays that special role
Then why not use any instead of Partial<any>?
all mapped types have the same behavior for primitives..
fair enough. As I said, I agree that the current behavior for mapped type is "likely" to be fine.
type X<T> = {
[P in keyof T]: T[P]
}
X<any> => { [P in keyof any]: any[P] } => { [P: string]: any }
My question is: should Partial and Readonly be just mapped type? Or should they be something more than a mapped type?
"a partial set of an infinite set is an infinite set"
"ready only of an infinite set is read only of an infinite set"
Mapped types in general are defined in terms of object types. in that context Readonly is an approximation of what a Readonly type operator would ideally mean. for instance Readonly<Array<T>> !== ReadonlyArray<T>, and so is Map and Set. so in that sense, i think Readonly<any> behaving as any in TS 2.5 was a bug, an unintentional behavior.
Yes, on that argument it does make sense for going against Readonly<any> => any
I'm almost convinced to drop Readonly<> from this discussion.
But on the other hand 馃槢 :
const x: Readonly<number> = 1
const y: Readonly<number & any> = 1 // error
any should be an inclusive of all types.
Maybe the special treatment needed for primitives is the root cause of this confusing behavior.
Maybe type Readonly<T extends object> = { ... } would avoid this problem altogether.
Need more time to think about Partial<any>
EDIT: while Readonly<> feels like a type operator, it is currently worked as mapped type, so:
let x: Readonly<{ foo: number }> => x: { readonly foo: number }
// !=
x: readonly { foo: number }
// or
x: readonly { readonly foo: number }
But
let x: Readonly<number> => x: number?
// or even
x: readonly number
that special treatment for primitive does create some problems. It feels like an escape clause then some actually desirable behaviors.
Maybe
type Readonly<T extends object> = { ... }would avoid this problem altogether.
we wanted to do that originally. but then 1. object was not in back then, and 2. felt annoying that every time you would write Partial<T> you have to make sure T extends object. So instead we have added the special handling of primitives. back then we did not really think of any deeply, and the behavior was rather unspecified. last release we fixed that, but really it should have been like so all along.
@kitsonk It's not always possible or convenient to define the type directly. sometimes you need to work with a third party tool, that returns Partial<T>. using any as the value of <T> should opt-out of type-checking during compilation.
@amir-arad
declare function foo<T>(bar: T): Partial<T>;
const baz: any = { qat: 1 };
const qat = foo(baz) as any;
// or
const qux: any = foo(baz);
It just requires you to be explicit about your any usage, which you should anyways.
@kitsonk as any has a tendency to stick around long after it's usefulness.
I don't think It's a good solution, explicitly opting out of type checks for the same piece of data, again and again in the same code block.
const baz: any = { qat: 1 };
const qat = func1(func2(foo(baz) as any) as any) as any; // this is not good code
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
anti-bot: this should be re-open for evaluation. 馃槢
It would be a breaking change but may worth the cost.
And ReadOnly and Partial may be treated differently, thus not a duplication.
https://github.com/gcanti/typelevel-ts/issues/19 suggested using conditional types to accomplish the desired behavior.
Most helpful comment
from the Documentation site :
I expect
Partialto be consistent in that matter with other type expressions, such as unions and intersections, whereanyplays that special role: