Traté de llamar a otra función sobrecargada dentro de una función sobrecargada en mecanografiado. Dado que el tipo Func2 es idéntico al tipo Func1 , es seguro que los argumentos pasados a func1 desde func2 se escribirán correctamente. Sin embargo, mecanografiado parece ser incapaz de detectarlo y arroja un error.
type Func1 = { (a: string, b: string): void (a: undefined, b: undefined): void } const func1: Func1 = (a, b) => { console.log(a, b) } type Func2 = { (a: string, b: string): void (a: undefined, b: undefined): void } const func2: Func2 = (a, b) => { func1(a, b) console.log(a, b) } /* No overload matches this call. Overload 1 of 2, '(a: string, b: string): void', gave the following error. Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'. Overload 2 of 2, '(a: undefined, b: undefined): void', gave the following error. Argument of type 'string | undefined' is not assignable to parameter of type 'undefined'. Type 'string' is not assignable to type 'undefined'. */¿Cómo puedo resolver esto?
EDITAR: Aquí está la implementación real que estaba intentando:
type ParseRandomArgs = { (a: undefined, b: undefined): [number, number] (a: number, b: undefined): [number, number] (a: number, b: number): [number, number] (a: [number, number], b: undefined): [number, number] (a: [number], b: undefined): [number, number] } type RandomNumber = { (a: undefined, b: undefined): number (a: number, b: undefined): number (a: number, b: number): number (a: [number, number], b: undefined): number (a: [number], b: undefined): number } const isNullish = (value: any) => value === undefined || value === null const parseRandomArgs: ParseRandomArgs = (a, b) => { if (Array.isArray(a)) { if (a.length === 2) return a return [0, a[0]] } else if (isNullish(b)) return [0, isNullish(a) ? 1 : a as number] else return [a as number, b as number] } const randomFloat: RandomNumber = (a, b) => { let [min, max] = parseRandomArgs(a, b) // [min, max] return Math.random() * (max - min) + min } const randomInt: RandomNumber = (a, b) => { let [min, max] = parseRandomArgs(a, b) // [min, max] min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min) + min) }No necesita duplicar sus parámetros o incluso usar afirmaciones: puede usar un predicado de tipo para permitir que el compilador discrimine los tipos nulos.
Y al usar tuplas etiquetadas para los parámetros, incluso puede obtener una mejor experiencia de desarrollador a través de útiles sugerencias de IntelliSense en su editor:
type Fn< Params extends unknown[] = any[], Result = any, > = (...args: Params) => Result; type CommonParams = [ [max?: number], [min: number, max?: number], [minAndMax: [min: number, max: number]], [maxOnly: [max: number]], ]; type ParseFn = Fn<CommonParams[number], [number, number]>; type RandomFn = Fn<CommonParams[number], number>; function isNullish <T>(value: T): value is Exclude<T, NonNullable<T>> { return value === undefined || value === null; } const parseRandomArgs: ParseFn = (...args) => { const [a, b] = args; if (Array.isArray(a)) return a.length === 2 ? a : [0, a[0]]; if (isNullish(a)) return [0, 1]; return isNullish(b) ? [0, a] : [a, b]; }; const randomFloat: RandomFn = (...args) => { const [min, max] = parseRandomArgs(...args); return Math.random() * (max - min) + min; }; const randomInt: RandomFn = (...args) => { let [min, max] = parseRandomArgs(...args); min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); };Creo que intentas hacer un código demasiado limpio.
Considerando el segundo ejemplo (con un número aleatorio): mecanografiado en realidad une todas las variantes posibles de argumentos
const randomInt: RandomNumber = (a, b) => { //a: number | [number, number] | [number] | undefined //b: number | undefined }y sus definiciones de RandomNumber/ParseRandomArgs solo se pueden usar para la validación de llamadas
entonces la primera solución es extender ParseRandomArgs con la unión de todos los argumentos
type ParseRandomArgs = { ... (a: [number]| [number, number] | number | undefined, b: number | undefined): [number, number] }segundo, mueva dicha unión a la función protegida y convierta ParseRandomArgs en un proxy
const _parseRandomArgs = function(a: [number] | [number,number] | number | undefined ,b?: number | undefined): [number,number]{ ... } const parseRandomArgs: ParseRandomArgs = (a, b) => { return _parseRandomArgs(a,b); } const randomFloat: RandomNumber = (a, b) => { let [min, max] = _parseRandomArgs(a, b) // [min, max] return Math.random() * (max - min) + min }y le sugiero que haga todos los argumentos indefinidos - opcional
código completo en Playground
Como mencionó @Mike, hacer que los argumentos undefined sean opcionales hace que la sobrecarga sea más fácil de resolver. Esto debería funcionar:
type RandomGenerator = { (start: number, end?: number): number (range: [number, number]): number; (range: [number]): number; } const randomFloat: RandomGenerator = (start, end?) => { const [min, max] = parseRandomArgs(start, end as number | undefined); return computeRandom(min, max); } const randomInt: RandomGenerator = (start, end?) => { const [min, max] = parseRandomArgs(start, end as number | undefined); return Math.floor(computeRandom(min, max)); } const computeRandom = (min: number, max: number): number => { return Math.random() * (max - min) + min; } const parseRandomArgs = (first: number | [number, number] | [number], second: number | undefined): [number, number] => { let args: [number, number]; if (Array.isArray(first) && first.length === 1) { args = [0, first[0]]; } else if (Array.isArray(first) && first.length === 2) { args = first; } else { args = Number.isFinite(second) ? [first, second as number] : [0, first]; } const [min, max] = args; return [Math.ceil(min), Math.floor(max)]; }