TypeScript의 주요 과제

여러 해 동안 일반적인 JavaScript를 한 후에 나는 최근에 TypeScript에서 득의양양할 기회가 생겼다.어떤 사람들은 대담하게 나에게 5분 안에 그것을 주울 것이라고 말했지만...내가 더 잘 알아.
대부분의 경우, 그것은 빠르고 들기 쉽다.그러나 새로운 범례로 전환하는 것은 항상 변두리 사례에 시달린다.TypeScript도 예외가 아닙니다.
나는 이미 내가 뛰어넘어야 할 장애에 관한 두 편의 긴 글을 썼다. 단지 React/TS가 React/JS와 같은 약정에서 기본 속성 값을 정의하도록 하기 위해서이다.나의 최신 난제는 대상 키의 처리와 관련이 있다.

문제


JavaScript를 사용할 때 항상 여러 객체를 처리해야 합니다.만약 당신이 어떤 JS 개발을 한 적이 있다면, 당신은 내가 대상을 이야기하는 방식이 자바 개발자가 대상을 이야기하는 방식과 다르다는 것을 알고 있습니다.내가 만난 대부분의 JS 대상은 Hashmaps와 같거나 더 이론적인 차원에서 원조인 것 같다.
예를 들어 나에게 이런 것처럼 보이는 두 개의 대상은 매우 흔하다.
const user1 = {
  name: 'Joe',
  city: 'New York',
  age: 40,
  isManagement: false,
};

const user2 = {
  name: 'Mary',
  city: 'New York',
  age: 35,
  isManagement: true,
};
그리 복잡한 것은 없지, 그렇지?그 물체들은 단지...데이터 구조.
지금 우리가 상상해 보자. 나는 항상 두 사용자의 공통점을 찾아야 한다.내 응용 프로그램은 항상 이런 평가를 필요로 하기 때문에, 나는 임의의 두 대상을 받아들일 수 있는 유니버설 함수를 만들고 이 대상들이 어떤 공통된 키 값을 가지고 있는지 알려주고 싶다.
JavaScript에서 다음과 같은 유틸리티 함수를 빠르게 생성할 수 있습니다.
const getEquivalentKeys = (object1: {}, object2 = {}) => {
   let equivalentKeys = [];
   Object.keys(object1).forEach(key => {
      if (object1[key] === object2[key]) {
         equivalentKeys.push(key);
      }
   });
   return equivalentKeys;
}
[주: 나는 좋은 .map() 함수를 사용하면 이 일을 더욱 효율적으로 완성할 수 있다는 것을 깨달았다. 그러나 나는 이 시범을 보면 이 점이 더욱 분명하다고 생각한다.
위의 기능을 사용하면 다음 작업을 수행할 수 있습니다.
console.log(getEquivalentKeys(user1, user2));
// logs: ['city']
함수 결과 user1user2가 공공도시를 공유한다는 것을 알려주었다.간단하죠??
TypeScript로 전환합니다.
const getEquivalentKeys = (object1: object, object2: object): Array<string> => {
   let equivalentKeys = [] as Array<string>;
   Object.keys(object1).forEach((key: string) => {
      if (object1[key] === object2[key]) {
         equivalentKeys.push(key);
      }
   });
   return equivalentKeys;
}
나는 이것이 보기에 괜찮다고 생각한다.TS는 그것을 좋아하지 않는다.구체적으로 TS는 이 행을 좋아하지 않습니다.
if (object1[key] === object2[key]) {
TS 표현:Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
은마르코프 모형...
명확하게 말하자면, 나는 인터페이스 정의 user 형식을 쉽게 사용할 수 있고, 함수 서명에서 그것을 설명할 수 있다는 것을 안다.하지만 나는 이 함수가 어떤 대상에도 사용될 수 있기를 바란다.나는 TS가 왜 그것을 불평하는지 이해하지만, 나는 절대로 그것을 좋아하지 않는다.TS는 어떤 종류의 색인 범용 object 을 사용해야 할지 모르기 때문에 불평한다.

범용과 싸우다


자바&C 개발을 마친 후, 나는 이것이 범용적인 용례라는 것을 즉시 깨달았다.그래서 한번 해봤어요.
const getEquivalentKeys = <T1 extends object, T2 extends object>(object1: T1, object2: T2): Array<string> => {
   let equivalentKeys = [] as Array<string>;
   Object.keys(object1).forEach((key: string) => {
      if (object1[key] === object2[key]) {
         equivalentKeys.push(key);
      }
   });
   return equivalentKeys;
}
그러나 이것은 이전 예시와 같은 문제를 초래할 수 있다.TS는 여전히 유형 string{} 인덱스일 수 있음을 알지 못합니다.나는 그것이 왜 불평하는지 이해한다. 왜냐하면:
const getEquivalentKeys = <T1 extends object, T2 extends object>(object1: T1, object2: T2): Array<string> => {
기능은 다음과 같습니다.
const getEquivalentKeys = (object1: object, object2: object): Array<string> => {
그래서 나는 더욱 명확한 배우를 시도했다. 예를 들면:
const getEquivalentKeys = <T1 extends object, T2 extends object>(object1: T1, object2: T2): Array<string> => {
   let equivalentKeys = [] as Array<string>;
   Object.keys(object1).forEach((key: string) => {
      const key1 = key as keyof T1;
      const key2 = key as keyof T2;
      if (object1[key1] === object2[key2]) {
         equivalentKeys.push(key);
      }
   });
   return equivalentKeys;
}
이제 TS는 이 분야에 대해 다시 한 번 불평합니다.
if (object1[key1] === object2[key2]) {
이번에는This condition will always return 'false' since the types 'T1[keyof T1]' and 'T2[keyof T2]' have no overlap.이것이 바로 내가 모니터를 향해 소리를 지르는 곳을 발견한 것이다.

Yes, they do have an overlap!!!


슬프게도 내 모니터는 묵묵히 나를 보고 있을 뿐이야...
즉, 신속하고 더러운 방법이 이를 실현할 수 있다.
const getEquivalentKeys = <T1 extends any, T2 extends any>(object1: T1, object2: T2): Array<string> => {
   let equivalentKeys = [] as Array<string>;
   Object.keys(object1).forEach((key: string) => {
      if (object1[key] === object2[key]) {
         equivalentKeys.push(key);
      }
   });
   return equivalentKeys;
}
봐라!TS는 더 이상 고소하지 않았습니다.하지만 TypeScript가 불평하지 않았을지도 모르지만, 나는 불평을 많이 한다.T1T2any로변환함으로써, 우리가 TS를 통해 얻어야 할 그 어떤 기묘한 마법도 기본적으로 파괴하기 때문이다. 만약 내가 이런 함수를 만들기 시작한다면, TS를 사용하는 것은 정말 의미가 없다. 왜냐하면 모든 것이 getEquivalentKeys()에 전달될 수 있기 때문이다. TS도 더 현명하지 못하기 때문이다.
드로잉 보드로 돌아가기...

인터페이스와 격투


일반적으로 TS 객체의 유형을 명시적으로 알려주려면 인터페이스를 사용할 수 있습니다.이로 인해 다음과 같은 결과가 발생합니다.
interface GenericObject {
   [key: string]: any,
}

const getEquivalentKeys = (object1: GenericObject, object2: GenericObject): Array<string> => {
   let equivalentKeys = [] as Array<string>;
   Object.keys(object1).forEach((key: string) => {
      if (object1[key] === object2[key]) {
         equivalentKeys.push(key);
      }
   });
   return equivalentKeys;
}
화목하다이것은 실행할 수 있다.에서 말한 바와 같이, 그것이 하는 것은 바로 우리가 그것을 기대하는 것이다.그것은 함수에만 대상을 전달할 것을 확보한다.
하지만 나는 진실을 말해야 한다. 이것은 정말 나를 화나게 한다.어쩌면, 몇 달만 더 지나면 나는 이것을 너무 신경 쓰지 않을 것이다.그러나 지금 어떤 이유로 나는 정말 화가 났다. 나는 TS에게 object 인덱스를 사용할 수 있다고 말해야만 했다.

컴파일러에 설명


이 시리즈의 첫 번째 문장에서 사용자는 멋진 평론을 제시했다(중점: 나의):

I'm a dyed in the wool C# programmer and would love to be pulling across the great parts of that to the JS world with TypeScript. But yeah, not if I'm going to spend hours of my life trying to explain to a compiler my perfectly logical structure.


잘했어, 마이크.잘했어.

왜 이게 나를 괴롭히지??


TS에 대해 가장 먼저 알아야 할 것은 JavaScript의 초집합이어야 한다는 것입니다.지금, 나는 네가 TS의 장점을 진정으로 이용하고 싶다면, 많은'기본'JS 코드가 TS 컴파일러가 좋아하지 않는 것임을 완전히 이해한다.
그러나 키 (일종의 유형: 문자열 키) 를 통해 인용된 대상의 값은 JS의 간단하고 기본적이며 핵심 부분이다. 나는 특수한 string 인터페이스를 만들어서 컴파일러에게 설명해야 한다고 곤혹스럽게 생각한다.

Yeah... this object can be indexed by a string.


내 말은, 이것은 매우 효과적이다.그러나 만약 이것이 내가 마땅히 해야 할 일이라면, 그것은 단지 나로 하여금 생각하게 할 뿐이다.

Wait... what???


만약 당신이 나에게 aGenericObject가 자모, 숫자, 특수 문자를 포함할 수 있다는 것을 TS에 설명해야 한다고 알려준다면 나도 같은 고민을 할 것이다.
이제 나는 그것을 어떻게 돌아가는지 이미 알고 있다. 나는 이것이 단지 네가 습관적으로 하는 일 중의 하나일 뿐이라고 생각한다.또는아마도 TS 중의 간단한 기술은 나로 하여금 이 문제를 돌이킬 수 있게 할 것이다. (TS의 핵심 우위를 약화시키지 않는다.)그러나 이 신기한 해결 방안이 존재한다면, 나의 보잘것없는 구글 검색 기술은 아직 밝혀지지 않았다.

좋은 웹페이지 즐겨찾기