TypeScript에서 객체 속성에 유형 추리를 해도 상위 객체 자체에 유형 추리가 적용되지 않습니다.

배경.


최근 개발에서는 왠지 타입스크립트의 형 추론 행위에 대해 생각만큼 적용형이 되지 않았지만, 이렇게 되면 조사 결과에 대한 지식이 생겨 기사를 썼다.

결론


먼저 결론을 진술하다.
TypeScript의 사양으로서 객체 속성에 유형 보호를 적용하여 유형을 추론해도 상위 객체 자체에 유형 추론을 적용하지 않습니다.

할 일


A형의 demodata 대상의 속성에서 각각undefined를 줄여서 함수testFunc의props로 보냅니다.if를 통과하면 형추론에서 B형의 조건을 충족시키는 것처럼 보이지만 if를 통과한 후 데모다타의 유형도 A형으로 처리되기 때문에testFunc의 매개 변수로 전달하면 오류가 발생할 수 있습니다.
type A = {
  name: string | undefined
  email: string | undefined
}

type B = {
  name: string
  email: string
}

const testFunc = (props: B): void => {
  console.log(props)
}

const demoData: A = {
  name: 'hoge',
  email: 'hoge'
}

// A 型の demoData のプロパティの型 name, email から、それぞれ undefined を省くように絞り込む
if (!demoData.name || !demoData.email) {
  throw 'error'
}

// error: Argument of type 'A' is not assignable to parameter of type 'B'.
testFunc(demoData)
https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UDeAoAkAOwIYFsIC4oBnYAJwEsMBzKAHygFcMATCAM0omfQhy3IA2hEhWp1GLdp24BfFClCQoAIQTJ02PMLKUqPPoO2i9clAGMA9hhJRgEEgDEmZtQAowpC2CKFlASkIANwtyZgQAPnUoaKhLawsBCAA6AQsqd09vPxRTOJtWHAsAESxgLEI4RFRMXAIoAHIACzSIeoAafX4hBuaqVpz5AHpB2ChAaPVAOwYoAuLSrCgJwHWGQFuGQEWGQDGGQGKGCbGoTQg2qF4uqEBpBkBIhkBABkBdBkAYhkA9BluJVg4MLihAJIZAQHdAeQZACIZAGIMgGsGQB6voAohkAPfGAAIYUOQ2FBXABCGYlMpJfZ0ejI3izNHHQR+KIxYCNTwAdwaEFInlI9QGKGGR2pFlIFVIVAYeAwwCgFnhimg9Rg9Sg5CIewsPKwRCI5Co2AARolbBYoGAsKRanZSLz+eBBcp6kkFPZgE4MGZXCi5tkgA

TypeScript 사양


먼저 Type Script는 구조적인 부분 언어라는 전제 조건이 있습니다.A형과 B형의 서명이 같으면 A형 대신 B형을 맡겨도 욕먹지 않는다는 것이다.
이번 사례에서 유형 보호의 영향을 받아 A형 속성의 유형에서 undefined를 배제했다. 유형에 따라 A형 혈액은 B형과 같은 인터페이스를 제공할 것으로 추정된다.시험해 보았는데 오류가 나서 이유를 모르고 막았다.
이 조사 결과에 관해서는 TypeScript의 issue에서 다음과 같은 논평이 발견되었다.
Type guards do not propagate type narrowings to parent objects. The narrowing is only applied upon access of the narrowed property which is why the destructing function works, but the reference function does not. Narrowing the parent would involve synthesizing new types which would be expensive.
유형 보호는 유형 나로식을 부모 대상에게 전파하지 않습니다.드롭다운 속성에 액세스하는 경우에만 적용됩니다.따라서 함수를 버리는 것은 작용하지만 참고 함수는 작용하지 않는다.부모를 줄이려면 합성 원가가 높은 새로운 유형이 필요하다.번역
https://github.com/microsoft/TypeScript/issues/31755#issuecomment-498669080
TypeScript의 규격으로서 형 보호를 했더라도 형 추론의 결과는 추론을 하는 대상 속성에만 적용되고 부 대상에는 적용되지 않는다.
TypeScript가 이를 지원하지 않는 이유는 비슷한 답변으로 다음과 같은 내용이 발견돼 붙여졌기 때문이다.(2021/12/30에 명시된 사양이 없는 문서)
  • 성능
  • In other words, in order to know the type of x we'd have to look at all type guards for properties of x.That has the potential to generate a lot of work.
    X형에 대한 정보를 알아보기 위해서는 X형의 모든 속성에 대한 방어 조사가 필요하다.그것은 대량의 처리가 발생할 가능성이 있다.번역
    https://github.com/Microsoft/TypeScript/pull/9163#issuecomment-226241452

    회피책


    그렇다면 A형 대상을 어떻게 B형으로 처리할까.따라서 이번 예는 다음과 같은 방법으로 회피할 수 있다.
  • 통과형 보호만으로 추론하는 속성을 매개 변수로 처리하는 방법
  • if (!demoData.name || !demoData.email) {
      throw 'error'
    }
    
    testFunc({name: demoData.name, email: demoData.email})
    
    https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UDeAoAkAOwIYFsIC4oBnYAJwEsMBzKAHygFcMATCAM0omfQhy3IA2hEhWp1GLdp24BfFClCQoAIQTJ02PMLKUqPPoO2i9clAGMA9hhJRgEEgDEmZtQAowpC2CKFlASgQAPnUoUKhLawsBCAA6AQsqd09vPxRTCJtWHAsAESxgLEI4RFRMXAIoAHIACwSISoAafX4hKtqqerT5cjYoVwBCLNz8rBjNaFp6Qd5hgpjeFoDUMNtqzwB3KohST1JKroV7YCcMM1ckccIhvLnxhqgFwyhrkfmDARlUoA
  • 유형 보호를 통해 사용자가 정의한 방식으로 부모 대상에게 유형을 단언하는 방법
  • const isB = (x: A | B): x is B => !!x.name && !!x.email;
    
    if (isB(demoData)) {
      testFunc(demoData);
    }
    
    https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UDeAoAkAOwIYFsIC4oBnYAJwEsMBzKAHygFcMATCAM0omfQhy3IA2hEhWp1GLdp24BfFClCQoAIQTJ02PMLKUqPPoO2i9clAGMA9hhJRgEEgDEmZtQAowpC2CKFlASgQAPnUoKEtrCwEIADoBCyp3T28-FFNwm1YcCwARLGAsQjhEVExcAigAcgALeIgKgBp9fiFKmqo61Pl04ChyIlVEVwAPQvF-QiHeohUgqABCOaHozWgAMlX5xejeZoBueXI2KFc+5VdMnLysPwDUULtHZ3PeS-y-fbkgA
    1의 예는 속성에 대해 추론을 하고 직접 사용하며 2의 예는 속성을 검증한 후 대상 자체에 대해 유형의 분배를 한다.
    추론 후 이용하고자 하는 속성이 제한적이라면 안전성을 중시하고 1을 선택해야 한다.확장성 및 가독성을 향상시키려면 2 를 선택합니다.등등 장소에 따라 구분해서 사용하는 것이 좋다.

    끝말


    평소 타입스크립트를 접하다 보니 습관이 된 사람인 줄 알았는데, 이번 조사로 아무것도 모른다는 걸 실감했다.
    새로운 발견이 있으면 언제든 여러분께 보내드리고 싶은 좋은 회고이기도 합니다.

    좋은 웹페이지 즐겨찾기