簡體   English   中英

預期有 3 個類型參數,但得到 1 個,但它應該推斷出 2 個類型

[英]Expected 3 type arguments but got 1 but it should infer 2 types

我想知道如何正確推斷我的函數的第二個和第三個模板

假設一個簡單的界面

interface ISome {
    a: string;
    b?: {
        c: string;
    };
}

關注作品

function pathBuilder<
    K1 extends keyof ISome,
    K2 extends keyof NonNullable<ISome[K1]>>(p: K1, p2?: K2) {
    let res = String(p);
    if (p2) { res += "." + p2; }
    return res;
}

const pathTest = pathBuilder("b", "c"); // ---> "b.c" and intellisense works on parameters

但我需要通過指定另一種類型來概括該函數以使其工作(我不想傳遞對象實例來指定類型)

所以,以下不起作用

function pathBuilder<
    T,
    K1 extends keyof T,
    K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) {
    let res = String(p);
    if (p2) { res += "." + p2; }
    return res;
}

const pathTest = pathBuilder<ISome>("b", "c"); // ERROR: Expected 3 type arguments, but got 1.ts(2558)

似乎函數的第 2 個和第 3 個模板參數不能從第一個參數推斷出來,但它應該是因為在第一種情況下,當我直接指定類型 T=ISome 時它起作用了。

我不確定是否有一些語言關鍵字可以使其工作,但模板應該完全適用:指定未知類型。

編輯

實際上我找到了這種方式,但需要額外的編碼,如果可能的話我會避免

function pathBuilder<T>() {
    return <
        K1 extends keyof T,
        K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) => {
        let res = String(p);
        if (p2) { res += "." + p2; }
        return res;
    };
}

const pathTest = pathBuilder<ISome>()("b", "c");

從 TS3.4 開始,沒有部分類型參數推斷 要么讓編譯器嘗試推斷所有類型參數,要么指定所有類型參數。 (嗯,有默認類型參數,但這並沒有給你你想要的:你想推斷你遺漏的類型參數,而不是為它們分配默認類型)。 已經有幾項提議來解決這個問題,但到目前為止,沒有一個得到完全批准

因此,目前只有解決方法。 我能想到的兩個是使用虛擬函數參數或使用currying

虛擬參數版本:

function pathBuilderDummy<
    T,
    K1 extends keyof T,
    K2 extends keyof NonNullable<T[K1]>>(dummy: T, p: K1, p2?: K2) {
    let res = String(p);
    if (p2) { res += "." + p2; }
    return res;
}

const pathDummyTest = pathBuilderDummy(null! as ISome, "b", "c");

在這里,我們正在做你說你不想做的事情……傳入一個T類型的參數。 但由於它只是一個虛擬參數而不是在運行時使用,所以它只與類型系統認為它是什么有關。 您傳入的值的實際類型無關緊要。 因此,您可以將其傳遞為null並使用類型斷言來選擇T

咖喱函數解決方案:

const pathBuilderCurry =
    <T>() => <
        K1 extends keyof T,
        K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) => {
        let res = String(p);
        if (p2) { res += "." + p2; }
        return res;
    }

const pathCurryTest = pathBuilderCurry<ISome>()("b", "c")

在這里,您正在返回一個返回另一個函數的函數。 第一個函數不接受任何值參數,但它接受您要指定的一個類型參數。 然后它返回一個函數,其中指定了T但推斷了其他類型參數。

這兩種解決方案都不是完美的,但它們是我們目前能做的最好的。 希望有所幫助; 祝你好運!

暫無
暫無

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

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