Repository navigation
Add typed overloads to Object.create #39882
Copy link
Copy link
Open
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Description
Search Terms
- object.create
- object create
- typed object.create
- typed object create
Suggestion
Change the signatures of Object.create to:
interface ObjectConstructor {
create<P extends object | null>(proto: P): null extends P ? {} : P;
create<
P extends object | null,
M extends PropertyDescriptorMap = {}
>(proto: P, properties?: M & ThisType<any>): {
readonly [
K in keyof M as M[K] extends { readonly writable: false }
? K
: never
]: M[K] extends Readonly<TypedPropertyDescriptor<infer V>>
? V
: any;
} & {
-readonly [
K in keyof M as M[K] extends { readonly writable: true }
? K
: never
]: M[K] extends Readonly<TypedPropertyDescriptor<infer V>>
? V
: any;
} & (null extends P ? {} : P);
}Use Cases
Getting correct types in code that does:
// `foo` is `any`, because `T` of Object.assign<T, U> is `any`:
const foo = Object.assign(
// `T` is currently typed as `any`:
Object.create(null),
// Only `U` is typed correctly as { bar: number; baz: string }:
{
bar: 123,
baz: 'biz',
},
);Examples
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This might need a flag similar to
strictBindCallApply, or just done in a separatelibfile.
- This might need a flag similar to
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
Relevant issues
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Activity
DanKaplanSES commentedon Sep 20, 2023
#3865 predates this one but was closed. I'm not sure why it was closed, but it might provide useful information.
@RyanCavanaugh replied:
I'd like to contribute my own use case (Stack Overflow link):
"I'm working on some legacy code I didn't write, trying to refactor it to typescript. ... writing the type definition by hand ... is quite painstaking, especially when the
Object.create[property] values ... are complex"DanKaplanSES commentedon Sep 20, 2023
ExE Boss (@ExE-Boss) I'm probably doing something wrong, but the overload isn't giving me the type I would expect when I use it like this.
lionel-rowe commentedon Apr 26, 2024
Surely this kind of use case is pretty common?
I guess typing
Object.create(null)as{}still wouldn't fix theundefinedissue, but that's a separate issue with TS's typing ofObject.fromEntries.Notably, simply defining
lookupObjasObject.fromEntries(arr.map(({ keyLike, ...rest }) => [keyLike, rest]))givesvalthe type{ prop1: string, prop2: number }, which is even less correct ifarbitraryStringhappens to be"constructor"or something.Edit: I know generally
Maps are better for this kind of use case, but sometimes a POJO is more convenient, e.g. easy JSON serialization or adding properties with nullish coalescing assignment??=.