簡體   English   中英

類屬性上的 TypeScript 聯合類型無法按預期工作

[英]TypeScript union type on class property does not work as expected

我正在嘗試為我們的模型類正確鍵入一個屬性包裝器,然后該屬性獲取一個代理設置器,該設置器被支持接受原始的、已解析的值和包裝器實例本身。 它本身的代碼已經可以工作,只是導致問題的輸入。 這個問題最好用代碼來解釋。

游樂場鏈接

屬性包裝器

abstract class BaseProp {}

type RawType = `/${string}/${number}` | null;
type ValType<M> = M | null | undefined;

type ResolvableProxy<M> = NonNullable<Resolvable<M> | RawType | ValType<M>>
class Resolvable<M> extends BaseProp {
    raw!: RawType;
    val!: ValType<M>;

    // has internal logic to resolve how to assign which is called via a proxy
    constructor (model: M) { super(); }

    resolve () {  return this; }
}

模型定義

class ModelA {
    name!: string;
}
class ModelB {
    a: ResolvableProxy<ModelA> = new Resolvable(ModelA);

    // the proxy handles properties that are extended from BaseProp
    // constructor () { return new Proxy(); }
}

這些模型被包裝到一個代理中,該代理對擴展BaseProp的所有內容都有特殊處理,我沒有包括那部分代碼,因為我認為它在這里不相關。 代理按預期工作,只有鍵入會導致問題。

測試用法

let test1: ResolvableProxy<ModelA> = new Resolvable(ModelA);
test1.resolve(); // accessable
const test1Name = test1.val!.name; // accessable
test1.raw = '/path/1'; // accessable
test1.val = new ModelA(); // accessable
test1 = '/path/1';
test1 = new ModelA();
test1 = new Resolvable(ModelA);

預期用途
當在類屬性上使用時,聯合類型的行為不同,對我來說沒有意義。

let test2 = new ModelB();
test2.a.resolve(); // not accessable, why?
test2.a.raw = '/path/1'; // not accessable, why?
test2.a.val = new ModelA(); // not accessable, why?
test2.a = '/path/1';
test2.a = new ModelA();
test2.a = new Resolvable(ModelA);

使用“as”允許訪問 Resolvable 成員,但這將需要重寫大量代碼,這不是必需的,因為類型本身應該是正確的 IMO。 當循環類似數組的結構時,它也會變得過於復雜。

(test2.a as Resolvable<ModelA>).raw = '/path/1';
const test3 = (test2.a as Resolvable<ModelA>).val;
(test2.a as Resolvable<ModelA>).resolve(); 

我考慮過為每個屬性使用顯式 getter/setter,但這會帶來其他問題,例如“a”不是 json 字符串化格式,至少在沒有額外處理的情況下是這樣。

export class ModelC  {
    // @ts-ignore
    #a: Resolvable<ModelA> = new Resolvable(ModelA);
    get a(): Resolvable<ModelA> { return this.#a; }

    set a(v: ResolvableProxy<ModelA>) { this.#a = v as any; }
}

const test4 = new ModelC();
test4.a.resolve();
test4.a.raw = '/path/1';
test4.a.val = new ModelA();
test4.a = '/path/1';
test4.a = new ModelA();
test4.a = new Resolvable(ModelA);

它在第一次測試中沒有出錯,因為它的類型被類型檢查器減少了

如果您破壞代碼塊,它將出錯

function testUsage() {
    let test1: ResolvableProxy<ModelA> = new Resolvable(ModelA);
    function f() {
        test1.resolve(); // error
        const test1Name = test1.val!.name; // error
        test1.raw = '/path/1'; // error
        test1.val = new ModelA(); // error
        test1 = '/path/1';
        test1 = new ModelA();
        test1 = new Resolvable(ModelA);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM