Associating data fields with discriminatory associations that cause errors

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[]?

+4
1

TypeScript. , :

function f(x: 'a' | 'b' | 'c'): { x: 'a' } | { x: 'b' } | { x: 'c' } {
    return { x: x };
}

// Type '{ x: "a" | "b" | "c"; }' is not assignable to type '{ x: "a"; } | { x: "b"; } | { x: "c"; }'.

. , 'a' | 'b' | 'c' x { x: 'a' | 'b' | 'c' } . , { x: 'a' } | { x: 'b' } | { x: 'c' }! , , 'a' | 'b' | 'c' { x: 'a' } | { x: 'b' } | { x: 'c' }.

. , :

function f(x: 'a' | 'b' | 'c'): { x: 'a' } | { x: 'b' } | { x: 'c' } {
    switch (x)
    {
        case 'a': return { x: x };
        case 'b': return { x: x };
        case 'c': return { x: x };
    }
}

case x ( 'a', 'b' 'c' ), { x: 'a' }, { x: 'b' } { x: 'c' } . { x: 'a' } | { x: 'b' } | { x: 'c' }.

, switch, , .

function f(x: 'a' | 'b' | 'c'): { x: 'a' } | { x: 'b' } | { x: 'c' } {
    return <any>{ x: x };
}

, TypeScript , { x: 'a' | 'b' | 'c' } { x: 'a' } | { x: 'b' } | { x: 'c' }. , -: ?

  • 'a' | 'b' | 'c' .
  • { x: 'a' } | { x: 'b' } | { x: 'c' } .
  • ({x: x}, resultType) , , .

:

foreach (t: Type in 'a' | 'b' | 'c')
{
    var checks = false;
    foreach (u: Type in { x: 'a' } | { x: 'b' } | { x: 'c' })
    {
        if ({ x: t } :<= u)
        {
            checks = true;
        }
    }
    if (!checks)
    {
        return false;
    }
}
return true;

O (n ^ 2)! , - , , { x: { y: 'a' | 'b' } | { y: 'c' | 'd' } } { x: { y: 'a' } } | { x: { y: 'b' } } | { x: { y: 'c' } } | { x: { y: 'd' } } - , .

, - . , , , , . - - . (, n + m, m + n, , , .)

+2

Source: https://habr.com/ru/post/1676178/


All Articles