简体   繁体   English

具有数组联合类型的打字稿接口

[英]typescript interface with array union type

Seems that this flags array for union type does not really work for me.似乎这个联合类型的标志数组对我来说并不适用。 I have been playing with idea that implementing class must provide flags about interfaces it's implementing which is also easy to get out from implementing class.我一直在考虑实现类必须提供关于它正在实现的接口的标志,这也很容易从实现类中脱离出来。 Flags as flags: Record<T & FeatureFlagType, true> works, but this also doable with array context?标志作为flags: Record<T & FeatureFlagType, true>有效,但这也适用于数组上下文? I have tried with all different combinations for flags like (T & FeatureFlag)[] but nothing seem to work.我已经尝试了所有不同的标志组合,如 (T & FeatureFlag)[] 但似乎没有任何效果。

type FeatureFlagType = 'feature1' | 'feature2';

interface FeatureFlag<T extends FeatureFlagType> {
    flags: T[];
    flagsRecords: Record<T, true>;
}

interface Feature1 extends FeatureFlag<'feature1'> {
    doFeature1: () => void;
}

interface Feature2 extends FeatureFlag<'feature2'> {
    doFeature2: () => void;
}

class Instance implements Feature1, Feature2 {
    public flags = ['feature1' as 'feature1', 'feature2' as 'feature2']; // not ok
    public flagsRecords = {feature1: true as true, feature2: true as true}; // this is ok
    public doFeature1() {

    }
    public doFeature2() {

    }
}

Playground 操场

implements enforces an intersection of types. implements强制类型的交集。 And the problem here is that:这里的问题是:

'a'[] & 'b'[] // never

So this will not work.所以这行不通。 What you want is a union of strings for the flags array, but implements will not do that for you.您想要的是flags数组的字符串联合,但implements不会为您执行此操作。

However an intersection will work with records:但是,交叉点将与记录一起使用:

Record<'a', string> & Record<'b', string> // { a: string, b: string }

Here's an alternative approach:这是另一种方法:

// See: https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type
type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

type FeatureFlagType = 'feature1' | 'feature2';

interface FeatureFlag<T extends FeatureFlagType> {
    flag: T;
}

type HasFeatures<T extends FeatureFlag<FeatureFlagType>[]> =
    { flags: T[number]['flag'][] }
    & UnionToIntersection<Omit<T[number], 'flag'>>


// intended usage:
class A implements HasFeatures<[Feature1, Feature2]> {
  //...
}

Now each feature has a single flag.现在每个功能都有一个标志。 The HasFeatures accepts an array of features, and makes an array of all possible features as the flags property. HasFeatures接受一个特征数组,并将所有可能的特征组成一个数组作为flags属性。

Then all non flag properties and intersected together and merged with the type, so the types gets all feature interfaces.然后将所有非flag属性相交并与类型合并,因此类型得到所有特征接口。

(In order to get the intersection of the array of feature interfaces, some voodoo is required) (为了得到特征接口数组的交集,需要一些巫术

But now this works as you would expect:但是现在这可以按您的预期工作:


interface Feature1 extends FeatureFlag<'feature1'> {
    doFeature1: () => void;
}

interface Feature2 extends FeatureFlag<'feature2'> {
    doFeature2: () => void;
}

class Instance implements HasFeatures<[Feature1, Feature2]> {
    public flags = [
        'feature1' as const,
        'feature2' as const
    ];
    public doFeature1() {

    }
    public doFeature2() {

    }
}

See playground 看游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM