簡體   English   中英

TypeScript:在映射對象中推斷特定類型的參數和函數的返回值

[英]TypeScript: Infer specific types of arguments and return values of functions in a mapped object

我正在嘗試為我的模塊構建一個類型保護的接口。

一個簡化的版本是這樣的:

const userResult = myFunc({
  foo: (key, arg) => {
    // users do something here with:
    //   - key inferred as "foo" and
    //   - arg inferred as string
    return "foobar";
  },
  bar: (key, arg) => {
    // users do something here with:
    //   - key inferred as "bar" and
    //   - arg inferred as number
    return 1;
  },
})

這里myFunc是我的模塊的接口函數。 用戶可以傳遞帶有任意鍵的對象(示例中的foobar )和特定類型的函數,其參數是keyarg ,返回值是字符串(示例中的"foobar" )或數字(示例中的1例子)。

我的目標是將arg的類型推斷為與函數的返回值相同的類型,同時將鍵的類型設置為與條目的key相同的字符串文字。

我已經為此苦苦掙扎了很長時間,但我設法發現它幾乎完美地工作:

type Value = string | number;
type MyType<K, T extends Value> = (key: K, arg: T) => T;

function myFunc<
  Ks extends keyof R,
  R extends { [K in Ks]: MyType<K, Value> },
>(
  userObj: {
    [K in Ks]: R[K];
  },
) {
  // do some complicated staffs
}

TypeScript 對示例用戶輸入的類型推斷結果為:

function myFunc<"foo" | "boo", {
    foo: (key: "foo", arg: Value) => string;
    boo: (key: "boo", arg: Value) => number;
}>(userObj: {
    foo: (key: "foo", arg: Value) => string;
    boo: (key: "boo", arg: Value) => number;
}): ResultType // whatever type we return

最后一個缺失點是arg被推斷為值,而不是特定類型(字符串為foo和數字為boo 。)

有什么解決辦法嗎? 任何提示或評論將不勝感激。

假設每個鍵的 arg 類型應該始終相同,定義映射類型可能很有用,然后從中派生您的類型。 在這種情況下, ParamValues是一個對象類型,我們將使用每個屬性的類型來對應函數 arg 的類型和返回值:

function myFunc<ParamValues>(userObj: {
  [K in keyof ParamValues]: (key: K, arg: ParamValues[K]) => ParamValues[K];
}) {
  // do something here
}

// Explicitly define the arg types per key
type SpecificValues = {
  foo: string,
  bar: number
}

myFunc<SpecificValues>({
  foo: (key, arg) => "Wa",
  bar: (key, arg) => arg + 1
})

// These fail because the operations being done on arg are not 
// supported by the value types from `SpecificValues`
myFunc<SpecificValues>({
  // @ts-expect-error
  foo: (key, arg) => arg * 3,
  // @ts-expect-error
  bar: (key, arg) => arg.slice(3),
  // @ts-expect-error
  baz: (key, arg) => arg + arg;
})

或者你可以使用類型推斷,但在某些時候你必須告訴編譯器你的類型是什么:

// This implies myFunc<{ blah: number, blag: string }>
myFunc({
  blah: (key, arg: number) => 4,
  blag: (key, arg: string) => "Woohoo!"
})

// This fails because return values do not match the arg types
myFunc({
  // @ts-expect-error
  blah: (key, arg: number) => "Yarg",
  // @ts-expect-error
  blag: (key, arg: string) => 3
})

簡而言之,我們的ParamValues類型不是任何變量實際擁有的類型; 它只是一種定義鍵到類型的映射的方法。

暫無
暫無

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

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