Reputation: 3072
Let's say I have an interface
interface FooBranchState {
a: string;
b: FooDiscriminator;
}
type FooDiscriminator = (value: any) => FooState;
I want to define FooState
to be a type or interface representing the following:
SingleFooBranchStateImpl
SingleFooBranchStateImpl
and also
I've currently got
export type FooState = FooEndState | FooBranchState
export type FooDiscriminator = (value: any) => FooState;
export type FooEndState = null;
export type FooBranchState = SingleFooBranchState | (SingleFooBranchState[])
export interface SingleFooBranchStateImpl {
foo: any;
next: FooDiscriminator;
}
export type SingleFooBranchStateFunction = () => SingleFooBranchStateImpl
export type SingleFooBranchState = SingleFooBranchStateImpl | SingleFooBranchStateFunction;
function test(value: FooState) {
console.log(value);
}
function getSingle(): FooState {
return {
foo: 1,
next: () => null
};
}
function getNull(): FooState {
return null;
}
function getArray(): FooState {
return [
getSingle(),
getSingle()
];
}
function getFunctionSingle(): FooState {
return () => ({
foo: 2,
next: () => null
});
}
function getFunctionArray(): FooState {
return () => ([{
foo: 3,
next: () => null
}]);
}
function getPromise(): FooState {
return Promise.resolve({
foo: 4,
next: () => null
});
}
But assigning a FooState[]
to FooState
requires a cast to FooState
, otherwise I get the below error. This makes me think there's something incorrect in my definition.
The error is:
Type 'FooBranchState[]' is not assignable to type 'FooBranchState'. Type 'FooBranchState[]' is not assignable to type 'SingleFooBranchState[]'. Type 'FooBranchState' is not assignable to type 'SingleFooBranchState'. Type 'SingleFooBranchState[]' is not assignable to type 'SingleFooBranchState'. Type 'SingleFooBranchState[]' is not assignable to type 'SingleFooBranchStateFunction'. Type 'SingleFooBranchState[]' provides no match for the signature '(): SingleFooBranchStateImpl'.
edit: corrected some typos in the original question (I was simplifying my actual code to a condensed example and made a couple errors).
As requested, here's an example: https://stackblitz.com/edit/typescript-xyag2s
edit2: Based on some of the comments on this, I have thought about this a little harder and came up with a more distilled example: http://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=18&pc=1#code/C4TwDgpgBAogtmUUC8UB2BXANlg3AWAChRIoANAJhSgGdgAnASzQHMDjxozrKoAfchQDaAXX6wEodkSIAzDGgDGwRgHs0UFhGABlZiywQAFAEoAXOSgBvKAHpbUAO6r6AaxpEoUetoz0NAOQAFowB7AC+MoTySirqmtoActhYphbcNvZOLu6e3r7+6CkRUTHKahpawACC9PQAhiBpljZ2DhB1LgA0UABGEIr1GDRcUIMa-UU4Pb0YwIJj9WgB85OYOHk+wH4aQl77B4deWdzjfdBLUPV1jVCqsoIzc1caZKLZ2AAmV1g0qmPqYD1Zh5LxVPSsQymI6HLJ7dZYHoBOhMVgBKAiPIiEqEOQKcrxKq1BogCjNDJtbJuDyELxbHZQIQrCB0ALYojhIA
type Empty = null;
type X2 = string;
type X = X2 | X2[] | Empty;
function getSingle(): X { // works
return 'hi';
}
function getNull(): X { // works
return null;
}
function getArray(): X { // error, because X can be null, but X2 can't be null
return [ // X can be an array of X2, but an X[] would also contain
getSingle() // [ null, 'string' ]
];
}
function getArray2(): X { // works
return ['test'];
}
In the simple example, it almost makes sense to declare getSingle as an X2
, but for my actual needs, I need to be able to return multiple variants from the same function.
Upvotes: 0
Views: 56
Reputation: 2720
It could be something like:
export type Foo = any;
export type FooState = null | Foo | Array<Foo> | FooDistriminator | FooDistriminatorPromise;
export type FooDistriminator = (value: any) => null | Foo | Array<Foo>;
export type FooDistriminatorPromise = (value: any) => Promise<null | Foo | Array<Foo>>;
Edit: In your stackblitz problem seems to be with your function typings for passed value and return value. I got it working like:
export type FooState = FooEndState | FooBranchState
export type FooDiscriminator = (value: any) => FooState;
export type FooEndState = null;
export type FooBranchState = SingleFooBranchState | Array<SingleFooBranchState> | Promise<SingleFooBranchStateImpl>
export interface SingleFooBranchStateImpl {
foo: any;
next: FooDiscriminator;
}
export type SingleFooBranchStateFunction = () => SingleFooBranchStateImpl
export type SingleFooBranchState = SingleFooBranchStateImpl | SingleFooBranchStateFunction;
function test(value: FooState) {
console.log(value);
}
function getSingle(): SingleFooBranchStateImpl {
return {
foo: 1,
next: () => null
};
}
function getNull(): FooState {
return null;
}
function getArray(): Array<SingleFooBranchState> {
return [
getSingle(),
getSingle()
];
}
function getFunctionSingle(): FooState {
return () => ({
foo: 2,
next: () => null
});
}
function getPromise(): Promise<SingleFooBranchStateImpl> {
return Promise.resolve({
foo: 4,
next: () => null
});
}
test(null);
test(getSingle());
test(getNull());
test(getArray());
test(getFunctionSingle());
test(getPromise());
Upvotes: 1