考慮一下(不編譯):
function roundTo<T = number | null | undefined>(
num: T,
decimals: number,
): T {
if (num === null || num === undefined) return num;
const factor = Math.pow(10, decimals);
return (Math.round(num * factor) / factor);
}
我想回傳傳遞給roundTo()
函式的相同型別。
例如:
const num1: number | null = 1.123456;
roundTo(num1, 1) // return type number | null
const num2: number = 1.123456;
roundTo(num2, 1) // return type number
const num3 = null;
roundTo(num3, 1) // return type null
的回傳型別roundTo
在編譯時是已知的,因此希望能夠根據第一個引數中傳遞的型別從那里攜帶型別。
我可以通過強制轉換回傳型別來進行編譯as any
,但這會破壞型別安全。我也可以通過使用extends
而不是=
和封裝回傳型別來進行編譯,但是它具有在傳入或傳入時as T
回傳的不良行為。any
null
undefined
如何讓 TypeScript 表現出所需的行為?
相關: https ://stackoverflow.com/a/51195834/188740 https://stackoverflow.com/a/57529925/188740
uj5u.com熱心網友回復:
應該是T extends ...
,不是T = ...
。后一種形式是“T的默認值”,它不是推斷出來的,而是總是被當作宣告的,基本上扼殺了整個想法。
function roundTo<T extends number | null | undefined>(num: T, decimals: number): T {
if (num == null) return num;
const factor = Math.pow(10, decimals);
return (Math.round((num as number) * factor) / factor) as T;
}
function test(x: number, y: null, z: undefined, t?: number, u?: null) {
let x1 = roundTo(x, 2); // -> number
let x2 = roundTo(y, 2); // -> null
let x3 = roundTo(z, 2); // -> undefined
let x4 = roundTo(t, 2); // -> number | undefined
let x5 = roundTo(u, 2); // -> null | undefined
}
實際上,您可以擺脫一種型別的強制num as number
,但可能不能擺脫另一種(至少不是一種簡單的方法)
function roundTo<T extends number | null | undefined>(num: T, decimals: number): T {
if (typeof num === 'number') {
// here typescript knows, that num is specific subtype of T - number
// but doesn't extend this to the T itself
const factor = Math.pow(10, decimals);
return Math.round(num * factor) / factor as T;
}
return num;
}
如果您真的想強制 typescript 在函式內推斷 T 的實際型別,則可能是條件型別,但恕我直言,這太過分了。
@Johnny Oshika 的另一點 - 為了避免不必要地縮小數字型別,可以使用多載:
function roundTo(num: number, decimals: number): number;
function roundTo<T extends number | null | undefined>(num: T, decimals: number): T;
function roundTo<T extends number | null | undefined>(num: T, decimals: number): T {
// function body
}
uj5u.com熱心網友回復:
這個答案歸功于@jcalz。
使用多載簽名設定條件回傳型別T extends number ? number : T
. 然后實作可以放寬型別推斷。
// Overload signature
export function roundTo<T extends number | null | undefined>(
num: T,
decimals: number,
): T extends number ? number : T;
// Implementation
export function roundTo(
num: number | null | undefined,
decimals: number,
) {
if (num === null || num === undefined) return num;
const factor = Math.pow(10, decimals);
return Math.round(num * factor) / factor;
}
例子:
roundTo(undefined, 2) // Returns type `undefined`
roundTo(null, 2) // Returns type `null`
roundTo(1.234 as number | undefined, 2) // Returns type `number | undefined`
roundTo(1.234 as number | null, 2) // Returns type `number | null`
roundTo(1.234, 2) // Returns type `number`
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/483543.html