I am working on an Ionic application (3.0.0) and often want to associate the types of two fields in the data interface. For example, a NotificationDatahas fields verb: 'mention' | 'share' | ...and reference: ProfileReference | DocumentReference | ..., but actually a NotificationDatais a union type:
{ verb: 'mention', reference: ProfileReference } | { verb: 'share', reference: DocumentReference }
So far so good. There are other fields that do not change using verb, so I usually create a basic interface, expand it differently, and then take a union, for example:
type X = 'a' | 'b' | 'c';
type Y = 'd' | 'e' | 'f';
interface I { x: X, other: Y };
interface A extends I { x: 'a', other: 'd' };
interface B extends I { x: 'b', other: 'e' };
interface C extends I { x: 'c', other: 'f' };
type J = A | B | C;
This is great as long as I hardcode the data
const j: J = { x: 'a', other: 'd' } // OK
or generating an integer from a switch
function f(x: X): J {
switch (x) {
case 'a': return { x, other: 'd' };
case 'b': return { x, other: 'e' };
case 'c': return { x, other: 'f' };
default: ((y: never) => {})(x);
}
}
// OK
But if I try to generate it in another way, Typescript complains:
function other(x: X): Y {
switch (x) {
case 'a': return 'd';
case 'b': return 'e';
case 'c': return 'f';
default: ((y: never) => {})(x);
}
}
function g(x: X): J {
return { x, other: other(x) }
}
// Error:
// Type '{ x: X; other: number; }' is not assignable to type Z.
// Type '{ x: X; other: number; }' is not assignable to type 'C'.
// Types of property 'x' are incompatible.
// Type 'X' is not assignable to type '"c"'.
// Type '"a"' is not assignable to type '"c"'.
In fact, these errors occur even if there is no data field relationship:
interface I2 { x: X, other: any };
interface A2 extends I2 { x: 'a' };
interface B2 extends I2 { x: 'b' };
interface C2 extends I2 { x: 'c' };
type J2 = A2 | B2 | C2;
function h(x: X): J2 { return { x, other: 0 }; }
// Error:
// Type '{ x: X; other: number; }' is not assignable to type J2.
// Type '{ x: X; other: number; }' is not assignable to type 'C2'.
// Types of property 'x' are incompatible.
// Type 'X' is not assignable to type '"c"'.
// Type '"a"' is not assignable to type '"c"'.
I could just use Iin my type signatures
const xs: X[] = ['a', 'b', 'c'];
const is: I2[] = xs.map(x => ({ x, other: 0 })) // OK
, . switch, function f ,
const js: J[] = xs.map(f); // OK
,
const j2s: J2[] = xs.map(x => ({ x, other: 0 }))
// Error: ... Type '"a"' is not assignable to type '"c"'.
, , Typescript /.
, : Typescript? J[] X[]?