Reputation: 3338
I'm working with a platform that requires me to define an object like this:
interface Source {
params: Params,
resolve: (props: ?) => string;
}
const source: Source = {
params,
resolve,
}
The params
object is defined like this:
interface Params {
[key: string]: 'text' | 'number';
}
and here's an example of it:
const params: Params = {
canonical_url: 'text',
published: 'text',
};
This object describes which and what types of params get passed to the resolve
function:
const resolve: string = (props: ?) => {...};
What I'd like to achieve is that the type of props
for the resolve
function is derived from the params
object. For the upper example, the resulting type would be:
interface Props {
canonical_url: string,
published: string,
}
The other option would be for this to work the other way round. So that the Props
type defines the object for params
, but that would mean that TS has to create an actual JS object from a type at transpile time, which I'm not sure is possible.
Upvotes: 0
Views: 49
Reputation: 414
You need to define your interfaces as generics:
type Text_ = "text";
type Number_ = "number";
interface Params<T extends Text_ | Number_> {
[key: string]: T;
}
interface Source<
T extends Text_ | Number_,
// this is where we conditionally map 'text' type literal to string type and 'number' to literal to number type
U = T extends Text_ ? string : T extends Number_ ? number : unknown
> {
params: Params<T>;
resolve: (props: U) => string;
}
const params: Params<Text_> = {
canonical_url: "text",
published: "text"
};
const source: Source<Text_> = {
params,
resolve: (props) => ""
};
source.resolve(""); // accepts string
source.resolve(1); // number is prohibited
Codesandbox example: https://codesandbox.io/s/unruffled-murdock-eoplg?file=/src/index.ts:0-527
Upvotes: 1