Reputation: 143
Not sure if this is possible or to best describe this, but I need to infer the literal type of a type that's already defined by another type/interface.
For example, I've got an object that adheres to a certain interface:
interface MyObject {
foo: string | number;
bar: string[];
}
const MY_OBJECT: MyObject = {
foo: 123,
bar: ["abc", "def"],
};
Now, what I'd like to know is the type literal of MY_OBJECT
, by doing something like this:
type MyObjectLiteral = Infer<typeof MY_OBJECT>;
That should make MyObjectLiteral
: { foo: 123, bar: ["abc", "def"] }
The question is how to define type Infer<T>
to return the inferred type of T
.
Any help or clarification would be appreciated.
Upvotes: 0
Views: 28
Reputation: 186994
This isn't really possible with types alone. A soon as you assign a value to a type that is wider than what could be inferred, you lose that type information.
But you can always treat a more narrow type as the wider type that includes it. Which means you can always go the other direction.
You could simply declare your object as const
and then use it anywhere that accepts a MyObject
type.
interface MyObject {
foo: string | number;
bar: readonly string[];
}
const myObject = { foo: 123, bar: ["abc", "def"] } as const
const barZero = myObject.bar[0] // type: "abc"
const myObjectWide: MyObject = myObject // works
const barWideZero = myObjectWide.bar[0] // type: string
Or if you want to constrain the construction of myObject
you can use a function to capture the exact subtype, and return it.
For example:
interface MyObject {
foo: string | number;
bar: readonly string[];
}
function makeObj<T extends MyObject>(myObject: T): T {
return myObject
}
const myBadObject = makeObj({ bad: true } as const)
// Argument of type '{ readonly bad: true; }' is not assignable to parameter of type 'MyObject'.
// Object literal may only specify known properties, and 'bad' does not exist in type 'MyObject'.(2345)
const myObject = makeObj({ foo: 123, bar: ["abc", "def"] } as const)
const barZero = myObject.bar[0] // type: "abc"
const myObjectWide: MyObject = myObject // works
const barWideZero = myObjectWide.bar[0] // type: string
Upvotes: 1