awesome-typescript icon indicating copy to clipboard operation
awesome-typescript copied to clipboard

「重学TS 2.0 」TS 练习题第二题

Open semlinker opened this issue 4 years ago • 33 comments

第二题

本道题我们希望参数 ab 的类型都是一致的,即 ab 同时为 numberstring 类型。当它们的类型不一致的值,TS 类型检查器能自动提示对应的错误信息。

function f(a: string | number, b: string | number) {
  if (typeof a === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return a + b; // error as b can be number | string
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

请在下面评论你的答案

semlinker avatar Sep 14 '21 15:09 semlinker

// 2 函数重载
type CustomType = string | number;
function f(a: number, b: number): number;
function f(a: string, b: string): string;

function f(a: number | string, b: number | string) {
  // 答案给的代码
  // if (typeof a === 'string') {
  //   return a + ':' + b;
  // } else {
  //   return (a as number) + (b as number);
  // }

  // 这样更直观一些
  if (typeof a === 'string' || typeof b === 'string') {
    return a + ':' + b;
  } else {
    return a + b
  }
}

f('s', 'k');
f('s', 1);
f(1, 'k');
f(1, 2)

pipeng119 avatar Sep 15 '21 06:09 pipeng119

2.1 函数重载

function f(a: string, b: string): string
function f(a: number, b: number): number
function f(a: string | number, b: string | number ): string | number {
  if (typeof a === 'string') {
    return a + ':' + b;
  } else {
    return ((a as number) + (b as number));
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

延伸阅读:TypeScript 函数重载

2.2 把参数组合成一种类型

const isStrArr = (a: string[] | number[]): a is string[] => typeof a[0] === 'string'

function f(...args: string[] | number[]) {
  if (isStrArr(args)) {
    return args[0] + ':' + args[1];
  } else {
    return args[0] + args[1];
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

semlinker avatar Sep 16 '21 01:09 semlinker

这样ok吗?

function f<T extends string | number>(a: T, b: T) {
  if (typeof a === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return (a as number) + (b as number); // error as b can be number | string
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f(2, 2) // Ok

cha0wg avatar Sep 18 '21 07:09 cha0wg

function add(a: number, b: number): number; function add(a: string, b: string): string; function add(a: string | number, b: string | number): string | number { if (typeof a === 'number' && typeof b === 'number') { return `${a}+${b}=${a + b}`; } else { return `${a}+${b}=${a}${b}`; } }

xiexingen avatar Sep 20 '21 06:09 xiexingen

function f(a: string, b: string): string
function f(a: number, b: number): number
function f(a: string | number, b: string | number) {
  if (typeof a === 'string') {
    return a + ':' + b // no error but b can be number!
  } else {
    return a + +b // error as b can be number | string
  }
}

f(2, 3) // Ok
f(1, 'a') // Error
f('a', 2) // Error
f('a', 'b') // Ok

Col0ring avatar Sep 20 '21 18:09 Col0ring

思路:首先用函数重载约束参数相同类型,然后再根据不同类型执行不同操作

function f(a: string, b: string): string
function f(a: number, b: number): number
function f(a: string | number, b: string | number) {
  if (typeof a === 'string') {
    return a + ':' + b // no error but b can be number!
  } else {
    return a + +b // error as b can be number | string
  }
}

f(2, 3) // Ok
f(1, 'a') // Error
f('a', 2) // Error
f('a', 'b') // Ok

yzycool avatar Sep 21 '21 13:09 yzycool

function f(...args: string[] | number[]) {
  if (typeof args[0] === 'string') {
    return args[0] + ':' + args[1]; // no error but b can be number!
  } else {
    return (args[0] as number) + (args[1] as number); // error as b can be number | string
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

mingzhans avatar Sep 21 '21 14:09 mingzhans

函数重载

function f(a: string, b: string): string
function f(a: number, b: number): number
function f(a: string | number, b: string |number) {
  if (typeof a === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return a + +b; // error as b can be number | string
  }
}

用元祖固定类型


type F = <T extends string | number>(...args: [T, T]) => string | number
const f: F = (a, b) => {
    if (typeof a === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return +a + +b; // error as b can be number | string
  }
}

xiaoYuanDun avatar Sep 22 '21 09:09 xiaoYuanDun

function f(a: string, b: string): string;
function f(a: number, b: number): number;
function f(a: string | number, b: string | number): string | number {
  if (typeof a === 'string' && typeof b === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else if (typeof a === 'number' && typeof b === 'number') {
    return a + b; // error as b can be number | string
  }
  throw Error('has error, a and b must be same type');
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

通过函数重载来实现不同类型参数的定义。同时调整原有的代码,增加一个兜底的throw error,这样在运行时也能有类型保护

zhaoxiongfei avatar Oct 01 '21 11:10 zhaoxiongfei

function f(a: string | number, b: string | number) { if (typeof a === 'string') { return a + ':' + b; } else { return b === 'number' ? a + b : a + '' + b; } }

console.log(f(2, 3)); console.log(f(1, 'a')); console.log(f('a', 2)); console.log(f('a', 'b'))

zw-zhuangwei avatar Oct 09 '21 07:10 zw-zhuangwei

// 使用函数重载可以实现 type types = string | number function f(a: string, b: string): string function f(a: number, b: number): number function f(a: types, b: types) { if (typeof a === 'string' || typeof b === 'string') { return a + ':' + b; // no error but b can be number! } else { return a + b; // error as b can be number | string } }

f(2, 3); // Ok f(1, 'a'); // Error f('a', 2); // Error f('a', 'b') // Ok

1938690786 avatar Oct 20 '21 08:10 1938690786

function f(a:number,b:number):number function f(a:string,b:string):string

function f(a: string | number, b: string | number) { if (typeof a === 'string') { return a + ':' + b; // no error but b can be number! } else if(typeof b === 'number'){ return a + b; // error as b can be number | string } }

f(2, 3); // Ok f(1, 'a'); // Error f('a', 2); // Error f('a', 'b') // Ok

xixisanmao avatar Nov 05 '21 09:11 xixisanmao

function f(a: number, b: number): number;
function f(a: string, b: string): string;

function f(a: number | string, b: number | string) {
  if (typeof a === "string") {
    return a + ":" + b;
  } else {
    return (a as number) + (b as number);
  }
}

f("s", "k");
f("s", 1);
f(1, "k");
f(1, 2);

lwt09 avatar Nov 19 '21 07:11 lwt09

type a = (x: string, y: string)=> string | number
type b = (x: number, y: number)=> string | number
const fn: a & b = (x, y) => {
  if(typeof x === 'string' || typeof y === 'string') {
    return x + ':' + y
  }
  return x + y
}

neptunedaxia avatar Nov 25 '21 03:11 neptunedaxia

function f(a: string, b:string): string; function f(a: number, b:number): number; function f(a: string | number, b: string | number): number | string { if (typeof a === 'string') { return a + ':' + b; // no error but b can be number! } else { return a + (b as number); // error as b can be number | string } }

pdc-cool avatar Dec 09 '21 08:12 pdc-cool

type T = number | string
function f(a: string, b: string): string
function f(a: number, b: number): number
function f(a: T, b: T) {
  if (typeof a === 'string') {
    return a + ':' + b;
  } else {
    return a + +b
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

waleiwalei avatar Dec 28 '21 05:12 waleiwalei

函数重载、类重载是 JS 的叛徒,能避免就避免,怎么能对同一个东西多次定义,然后在调用时去做选择。 这是偷懒,把麻烦后置。

最后为了逻辑更健壮,可以利用never特性,来避免没有穷尽的情况。

function f<T extends string | number>(a: T, b: T) {
  if (typeof a === 'string') {
    return a + ':' + b
  } else if (typeof a === 'number') {
    return (a as number) + (b as number)
  } else {
    const check: never = a
    return ''
  }
}

junbin123 avatar Feb 27 '22 05:02 junbin123

image

codeyourwayup avatar Mar 27 '22 04:03 codeyourwayup

image

codeyourwayup avatar Mar 27 '22 04:03 codeyourwayup

function f<T extends string | number>(a: T, b: T) { if (typeof a === 'string') { return a + ':' + b; // no error but b can be number! } else { return (a as number) + (b as number); // error as b can be number | string } }

没有必要用T;因为T extend string | number没有意义;因为T就是 string | number;没有必要extend。这个方法不好。

codeyourwayup avatar Mar 27 '22 05:03 codeyourwayup

type stringOrnumber=string|number

function f<T extends stringOrnumber>(a:T,b:T):stringOrnumber { if (typeof a === 'string') { return a + ':' + b; // no error but b can be number! } else { return (a as number) + (b as number); // error as b can be number | string } }

f(2, 3); // Ok console.log(f(1, 'a')); // Error console.log(f('a', 2)); // Error f('a', 'b') // Ok

export default {}

lisongyu avatar Apr 11 '22 09:04 lisongyu

// 类型约束
type Type = string | number
function f<T extends Type>(a: T, b: T) {
    if (typeof a === 'string') {
      return a + ':' + b; // no error but b can be number!
    } else {
      return (a as number) + (b as number); // error as b can be number | string
    }
  }
  
  f(2, 3); // Ok
  f(1, 'a'); // Error
  f('a', 2); // Error
  f('a', 'b') // Ok

//   函数重载
type sign = number | string 
function f(a:number, b:number):number
function f(a:string, b:string):string
function f(a:sign, b:sign): sign {
    if(typeof a === 'string'){
        return a + '' +b // no error but b can be number!
    }
    else {
        return (a + (b as number)) // error as b can be number | string
    }
}

  f(2, 3); // Ok
  f(1, 'a'); // Error
  f('a', 2); // Error
  f('a', 'b') // Ok

YJCCreateAHistory avatar May 23 '22 02:05 YJCCreateAHistory

function f(a: string | number, b: string | number) {
  if (typeof a === 'string' && typeof b === 'string') {
    return a + ':' + b;
  } else if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
}

运行时需要校验的地方, 就应该交给运行时来判断

ChangerHe avatar May 26 '22 11:05 ChangerHe

function f(a: string | number, b: string | number) {
  if (typeof a === 'string' && typeof b === 'string') {
    return a + ':' + b;
  } else if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  }
}

运行时需要校验的地方, 就应该交给运行时来判断

这个好像不行喔,有报错Not all code paths return a value.

creakps avatar Jun 13 '22 06:06 creakps

函数重载、类重载是 JS 的叛徒,能避免就避免,怎么能对同一个东西多次定义,然后在调用时去做选择。 这是偷懒,把麻烦后置。

最后为了逻辑更健壮,可以利用never特性,来避免没有穷尽的情况。

function f<T extends string | number>(a: T, b: T) {
  if (typeof a === 'string') {
    return a + ':' + b
  } else if (typeof a === 'number') {
    return (a as number) + (b as number)
  } else {
    const check: never = a
    return ''
  }
}

确实这才是比较好的做法

Wuyuhao233 avatar Jun 21 '22 06:06 Wuyuhao233

function f(a: string | number, b: string | number):string|number { if (typeof a === 'string'&&typeof b === 'string') { return a + ':' + b; // no error but b can be number! } else if(typeof a === 'number'&&typeof b === 'number') { return a + b; // error as b can be number | string }else{ throw Error } }

f(2, 3); // Ok f(1, 'a'); // Error f('a', 2); // Error f('a', 'b') // Ok

keshengwang avatar Jul 28 '22 07:07 keshengwang

function f(a: string, b: string) : string
function f(a: number, b: number) : number
function f(a: any, b: any) {
  if (typeof a === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return a + b; // error as b can be number | string
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

dolphin0618 avatar Aug 06 '22 08:08 dolphin0618

//  函数重载
function f(a: string, b: string): void;
function f(a: number, b: number): void;
function f(a: string | number, b: string | number) {
  if (typeof a === 'string') {
    return `${a}:${b}`; // no error but b can be number!
  }
  return a + b; // error as b can be number | string
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b'); // Ok


fishcoderman avatar Aug 24 '22 15:08 fishcoderman

function f<T extends string | number>(a: T, b: T) {
  if (typeof a === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return (a as number) + (b as number); // error as b can be number | string
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

SmileHeart1996 avatar Sep 14 '22 06:09 SmileHeart1996

不改动源代码好像不行

function f(a: string, b: string): string
function f(a: number, b: number): number
function f(a: string | number, b: string | number) {
  if (typeof a === 'string' || typeof b === 'string') {
    return a + ':' + b; // no error but b can be number!
  } else {
    return a + b; // error as b can be number | string
  }
}

f(2, 3); // Ok
f(1, 'a'); // Error
f('a', 2); // Error
f('a', 'b') // Ok

sansan-mei avatar Oct 19 '22 03:10 sansan-mei