参考链接
TS 中的!和?用法
TS 官方文档

# TS 中的!和?的用法

# !的用法

{
  // 用在赋值的内容时,使 null 和 undefined 类型可以赋值给其他类型并编译通过
  // 表示该变量值可空
  let y: number;
  let a: string;
  //  y = null		    //  无法通过编译
  //  y = undefined	    //  无法通过编译
  y = null!;
  y = undefined!;
  a = null!;
  console.log('y', y); // undefined
  console.log('a', a); // null
}
{
  interface IDemo {
    x?: number; // ? 表示 x 为可选的
  }
  let y: number;
  // 无法传递给类型为 number 的 y,因此需要用!
  const demo = (param: IDemo) => {
    // 由于 x 为可选的,因此 param.x 的类型可能为  number | undefined
    y = param.x!; // 强制 赋值给 y
    return y;
  };
  // {x: 2} 可传可不传,但是不能不传,可传空对象 {},这里指的是接口参数表示可选
  console.log('demo----->', demo({ x: 2 })); // demo-----> 2
}

# ? 用法

除了表示 可选 参数外,常常用于防御性编程

{
  const a = { b: { c: 0 } } || {}; // 假设 a 是从后端拿到的一个对象类型数据
  const tableData = a.b.c; // 这样写不安全,无法确保 b 是否有值,如果为 空 则 b.c 会进行报错
  const testData = a?.b?.c; // 实际上就是相当于 const testData = a && a.b && a.b.c
  // 当使用 a 对象属性 a.b 时,如果无法确定 a 是否为空,则需要用 a?.b
  // 表示当 a 有值的时候才去访问 b 属性,没有值的时候就不去访问,如果不使用?则会报错
}
{
  interface IDemo {
    x: number;
  }
  let y: number;
  // 由于函数参数可选,因此 parma 无法确定是否拥有
  // (parameter) parma: IDemo | undefined
  const demo2 = (parma?: IDemo): number => {
    // 所以无法正常使用 parma.x,使用 parma?.x 向编译器假设此时 parma 不为空且为 IDemo 类型,
    // 同时 parma?.x 无法保证非空,因此使用 parma?.x! 来保证了强制赋值并整体通过编译
    y = parma?.x!;
    console.log('parma?.x---->', parma?.x); //  parma?.x----> undefined | 7
    return y;
  };
  console.log('demo2----->无参', demo2()); //  demo2-----> 无参 undefined
  console.log('demo2----->有参', demo2({ x: 7 })); //  demo2-----> 有参 7
}

# 示例

{
  // 接口里的属性不全都是必须的。有些是只在某些条件下存在,或者根本不存在。
  interface SquareConfig {
    color?: string; // 表示可选
    width?: number; // 表示可选
  }
  // : {color: string; area: number} 表示返回值参数类型
  //  config? 表示参数也是可选
  const createSquare = (
    config?: SquareConfig
  ): { color: string; area: number } => {
    const newSquare = { color: 'red', area: 100 };
    if (config?.color) {
      newSquare.color = config.color;
    }
    if (config?.width) {
      newSquare.area = config.width * config.width;
    }
    return newSquare;
  };
  // 由于 createSquare 的参数对象中属性是可选的,所以可传部分属性,或者是不传,具体看接口对象属性
  console.log(
    'createSquare---->传部分参数属性',
    createSquare({ color: 'black' })
  ); // {color: "black", area: 100}
  console.log('createSquare---->传空对象参数', createSquare({})); // {color: "red", area: 100}
  console.log('createSquare---->无参', createSquare()); // {color: "red", area: 100}
}

# 结语

永远不要相信苦难是值得的,苦难就是苦难,苦难不会带来成功,苦难不值得追求,磨炼意志是因为苦难无法躲开。 ————《活着》