First, I'll just provide some background info:
I have the two interfaces that both inherit off of a common base.
interface Base { type: string }
interface Foo extends Base { type: "foo", name: string }
interface Bar extends Base { type: "bar", score: number }
I keep both in a union type so I can use it in an array that stores either of the two.
type Baz = Foo | Bar;
const storage : Baz[] = [];
I have a type which stores all possible values of type
for the union type, and a function that only accepts those values.
type BazTypes = Baz["type"]; // "foo" | "bar"
function readBaz(type : BazTypes) { /* ... */ }
Now, I'm trying to make a map of functions that will parse a given object as presented by Baz
, given its type, like so:
// Expectation:
{
"foo": (arg : Foo) => boolean, // (arg: {type: "foo", name: string}) => boolean
"bar": (arg : Bar) => boolean, // (arg: {type: "bar", score: number}) => boolean
}
type BazMap = {
[key in BazTypes]: (args : Baz extends {type: key} ? Baz : never) => boolean
};
const parsers : BazMap = {
"foo": (foo /* which should be of type Foo */) => { /* ... foo.name ... */ },
"bar": (bar /* which should be of type Bar */) => { /* ... bar.score ... */ },
}
However, that map instead provides the union type itself instead of the correct interface for the given type.
// Reality:
{
"foo": (arg : Foo | Bar) => boolean,
"bar": (arg : Foo | Bar) => boolean
}
type BazMap = {
[key in BazTypes]: (args : Baz extends {type: key} ? Baz : never) => boolean
};
const parsers : BazMap = {
"foo": (foo /* which is Foo | Bar */) => { /* Only foo.type can be accessed. */ },
"bar": (bar /* which is Foo | Bar */) => { /* Only bar.type can be accessed. */ },
}
Because of this, TypeScript does not provide me either name
and score
since either value does not exist in both Foo
nor Bar
.
I am trying to get the map as I expected. So far, I haven't been able to properly create a map that accepts the correct type.
TL;DR: How can I create a Object type based on the parameter of a type? (e.g. If the type is "foo"
, it will return a parser for Foo
(that doesn't accept Bar
), etc.)