TypeScript 소개

게시 됨: 2020-10-29

내가 프로그래밍한 첫 번째 언어는 C와 Java입니다. 이러한 언어를 사용하면 변수를 정의할 때마다 유형을 지정해야 합니다. 다른 유형의 값을 할당하려고 하면 컴파일러에서 다음과 같이 불평합니다.

 // main.c int main() { int x = "two"; return 0; } > cc main.c -o main // warning: initialization makes integer from pointer without a cast

문제는 내 경험 부족으로 인해 컴파일러로부터 받은 많은 불만 사항이 비밀스럽고 복잡해 보였다는 것입니다. 그렇기 때문에 결국 컴파일러를 내 창의성을 제한하는 도구로 보았지만 실제로는 도움을 주는 파트너가 되어야 했습니다.

Sponge Bob이 컴퓨터를 충돌시키는 Gif

나중에 경력을 쌓으면서 JavaScript나 PHP와 같은 강력한 타이핑 없이 일부 프로그래밍 언어를 사용하기 시작했습니다. 나는 그것들이 꽤 멋지다고 생각했습니다. 까다로운 컴파일러를 다룰 필요 없이 빠르게 프로토타입을 만드는 것이 매우 쉬웠습니다.

이미 알고 있듯이 WordPress의 기반이 되는 프로그래밍 언어는 PHP와 JavaScript입니다. 이것은 컴파일러가 뒤를 돌아보지 않고 플러그인과 테마를 코딩하는 데 익숙할 수 있음을 의미합니다. 오직 당신, 당신의 기술, 그리고 당신의 창의성뿐입니다. 음, 다음과 같은 오류:

 const user = getUser( userId ); greet( user.name ); // Uncaught TypeError: user is undefined

코드에 undefined 버그가 있는 경우에는 워크플로에 컴파일러를 추가해야 합니다. TypeScript가 무엇이며 어떻게 이를 통해 소프트웨어 품질을 몇 배나 향상시킬 수 있는지 살펴보겠습니다.

타입스크립트란?

TypeScript는 강력하고 정적인 타이핑을 추가하기 위해 만들어진 JavaScript 기반 프로그래밍 언어입니다. TypeScript 유형을 사용하면 객체와 변수의 모양을 설명할 수 있으므로 문서화되고 더 강력한 코드가 생성됩니다. TypeScript 자체가 우리가 하는 모든 일을 검증할 책임이 있습니다.

설계된 대로 TypeScript는 JavaScript의 상위 집합입니다. 즉, 일반 JavaScript로 작성된 모든 코드는 정의상 유효한 TypeScript이기도 합니다. 그러나 그 반대는 사실이 아닙니다. TypeScript 관련 기능을 사용하는 경우 결과 코드는 변환할 때까지 유효한 JavaScript가 아닙니다.

TypeScript 작동 방식

TypeScript의 작동 방식을 이해하기 위해 TypeScript 코드를 작성하고 컴파일러가 이에 대해 알려주는 내용을 볼 수 있는 작은 편집기인 Playground 를 사용할 것입니다.

JavaScript의 상위 집합이기 때문에 TypeScript 코드를 작성하는 것은 매우 쉽습니다. 기본적으로 다음 JavaScript 코드:

 let user = "David"; let age = 34; let worksAtNelio = true; console.log( user, age, worksAtNelio );

TypeScript 코드이기도 합니다. TypeScript Playground에서 복사하여 붙여넣을 수 있으며 컴파일되는 것을 볼 수 있습니다. 그래서 무엇이 그렇게 특별한가요? 물론 그 유형. JavaScript에서는 다음을 수행할 수 있습니다.

 let user = "David"; let age = 34; let worksAtNelio = true; user = { name: "Ruth" }; console.log( user, age, worksAtNelio );

그러나 TypeScript에서 오류가 발생합니다. Playground에서 시도하면 다음 오류가 표시됩니다.

 Type '{ name: string; }' is not assignable to type 'string'.

그래서 그게 다야?

TypeScript는 변수의 유형을 자동으로 유추할 수 있습니다. 즉, "이 변수는 문자열"(또는 숫자, 부울 등)이라고 명시적으로 말할 필요가 없습니다. 대신, 처음에 주어진 값을 보고 이를 기반으로 유형을 유추합니다.

좋은 아이디어를 가진 남자의 Gif

이 예에서 user 변수를 정의할 때 "David" 텍스트 문자열을 할당했기 때문에 TypeScript는 userstring 임을 알 수 있습니다. 문제는 조금 후에 값이 "Ruth" 문자열 인 단일 속성( name )을 가진 객체를 할당하여 user 변수의 유형을 변경하려고 한다는 것입니다. 분명히 이 객체는 string 이 아니므로 TypeScript는 할당을 수행할 수 없다고 불평합니다.

이 문제를 해결할 수 있는 두 가지 경로가 있습니다.

 // Option 1 let user = "David"; user = "Ruth"; // OK. // Option 2 let user = { name: "David" }; user = { name: "Ruth" };

변수의 유형을 정의할 때 명시합시다.

그러나 유형 추론은 우리를 돕기 위한 것일 뿐입니다. 원하는 경우 TypeScript에 변수 유형을 명시적으로 알릴 수 있습니다.

 let user: string = "David"; let age: number = 34; let worksAtNelio: boolean = true; console.log( user, age, worksAtNelio );

TypeScript에서 유추한 유형과 정확히 동일한 결과를 렌더링합니다. 이제 이것이 질문을 던집니다. TypeScript가 자동으로 유형을 유추할 수 있다면 이 기능이 왜 필요한가요?

한편으로 유형을 명시적으로 지정하면 코드를 더 잘 문서화할 수 있습니다(다음 섹션에서 더 명확해짐). 반면에 유형 추론 시스템의 한계를 해결할 수 있습니다. 네, 맞습니다. 추론이 매우 좋지 않고 TypeScript가 할 수 있는 최선의 방법은 “글쎄요, 이 변수가 정확히 무엇이어야 하는지 모르겠습니다. 무엇이든 될 수 있을 것 같아요!”

다음 예를 고려하십시오.

 const getName = ( person ) => person.name; let david = { name: "David", age: 34 }; console.log( getName( david ) ); // Parameter 'person' implicitly has an 'any' type.

이 경우 매개변수를 수신하고 값을 리턴하는 getName 함수를 정의하고 있습니다. 우리가 이 간단한 함수에서 얼마나 많은 것을 가정하는지 주목하세요. 우리는 name 이라는 속성이 하나 이상 있는 객체( person )를 기대하고 있습니다. 그러나 이 함수를 호출한 사람이 이 함수를 적절하게 사용할 것이라는 보장은 전혀 없습니다. 하지만 그렇게 한다 해도 우리는 여전히 이 함수의 결과 유형이 무엇인지 모릅니다. 물론, 이름문자열 일 것이라고 가정할 수도 있지만, 당신은 인간이고 그 단어의 의미를 이해하기 때문에 그 사실을 알고 있을 뿐입니다. 그러나 다음 예를 보십시오.

 getName( "Hola" ); // Error getName( {} ); // Returns undefined getName( { name: "David" } ); // Returns a string getName( { name: true } ); // Returns a boolean

함수를 호출할 때마다 다른 결과를 얻습니다! 따라서 TypeScript가 우리를 감시하고 있음에도 불구하고 여전히 고전적인 JavaScript 문제에 직면해 있습니다. 이 함수는 무엇이든 받을 수 있고 무엇이든 반환할 수 있습니다.

아기가 매우 슬퍼하는 재미있는 gif

해결책은 함수에 명시적으로 주석을 추가하는 것입니다.

자신의 유형 정의

하지만 그 전에 또 다른 TypeScript 기능인 사용자 정의 데이터 유형을 살펴보겠습니다. 지금까지 우리의 거의 모든 예제는 string , number , boolean 등과 같은 기본 유형을 사용했으며, 이는 이해하기 매우 쉽다고 생각합니다. 객체와 같은 더 복잡한 데이터 구조도 보았습니다.

 let david = { name: "David", age: 34 };

하지만 TypeScript에 의해 유추된 유형에는 그다지 주의를 기울이지 않았습니다. 그렇죠? 우리가 본 것은 타이핑 불일치로 인한 잘못된 할당의 예입니다.

 let user = "David"; user = { name: "Ruth" }; // Type '{ name: string; }' is not assignable to type 'string'.

이것은 어떻게든 객체의 유형이 " {name:string;} "임을 암시하며, "이것은 string 유형의 이름 이라는 속성을 가진 객체 입니다."라고 읽을 수 있습니다. 이것이 객체 유형이 정의되는 방식이라면 다음은 유효한 TypeScript여야 합니다.

 let david: { name: string, age: number } = { name: "David", age: 34 };

그리고 그것은 사실이다. 그러나 당신은 그것이 결코 편리하지 않다는 데 동의할 것이라고 확신합니다. 다행히 TypeScript에서 새 유형을 만들 수 있습니다.

일반적으로 사용자 정의 유형은 기본적으로 사용자 정의 이름이 있는 일반 TypeScript 유형입니다.

 type Person = { name: string; age: number; }; let david: Person = { name: "David", age: 34 };

멋지다, 응? 이제 Person 유형이 있으므로 getName 함수에 쉽게 주석을 달고 입력 매개변수의 유형을 명확하게 지정할 수 있습니다.

 const getName = ( person: Person ) => person.name;

그리고 이 간단한 업데이트는 TypeScript에 많은 정보를 제공합니다! 예를 들어 Person 객체의 name 속성도 string 이라는 것을 확실히 알고 있기 때문에 이제 이 함수의 결과 유형이 string 임을 추론할 수 있습니다.

 let david: Person = { name: "David", age: 34 }; let davidName = getName( david ); davidName = 2; // Type 'number' is not assignable to type 'string'.

그러나 항상 그렇듯이 다음을 수행하려는 경우 결과 유형에 명시적으로 주석을 달 수 있습니다.

 const getName = ( person: Person ): string => person.name;

TypeScript 유형에 대한 추가 정보…

마지막으로 TypeScript에서 고유한 유형을 정의할 때 이점을 얻을 수 있는 몇 가지 흥미로운 기능을 공유하고 싶습니다.

TypeScript는 변수에 값을 할당할 때 매우 까다롭습니다. 특정 변수의 유형을 명시적으로 정의한 경우 해당 유형과 정확히 일치하는 값만 할당할 수 있습니다. 몇 가지 예를 들어 살펴보겠습니다.

 type Person = { name: string; age: number; }; let david: Person = { name: "David", age: 34 }; // OK let ruth: Person = { name: "Ruth" }; // Property 'age' is missing in type '{ name: string; }' but required in type 'Person' let toni: Person = { name: "Toni", age: 35, gender: "M" }; // Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'. Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

보시다시피 Person 변수는 Person 유형을 완전히 준수하는 개체만 허용합니다. 일부 속성이 누락되었거나( ruth 에는 age 이 없음) 유형에 포함된 것보다 더 많은 속성이 있는 경우( toni 에는 gender 이 있음) TypeScript는 불평하고 유형 불일치 오류를 트리거합니다.

그러나 함수 호출에 대해 이야기하고 있다면 상황이 다릅니다! 함수의 인수 유형은 정확한 요구 사항은 아니지만 매개 변수가 준수해야 하는 최소 인터페이스를 지정합니다. 나도 알아, 나도 알아, 그건 너무 추상적이야. 다음 예를 살펴보겠습니다. 그러면 상황이 더 명확해질 것입니다.

 type NamedObject = { name: string; }; const getName = ( obj: NamedObject ): string => obj.name; const ruth = { name: "Ruth" } getName( ruth ); // OK const david = { name: "David", age: 34 }; getName( david ); // OK const toni = { firstName: "Toni" }; getName( toni ); // Argument of type '{ firstName: string; }' is not assignable to parameter of type 'NamedObject'. Property 'name' is missing in type '{ firstName: string; }' but required in type 'NamedObject'.

보시다시피 getName 함수를 좀 더 일반적인 것으로 재정의했습니다. 이제 NamedObject 개체, 즉 name 유형의 string 속성이 있어야 하는 개체를 사용합니다. 이 정의를 사용하여 ruthdavid 가 이 요구 사항(둘 다 name 속성을 가짐)과 어떻게 완벽하게 일치하는지 알 수 있지만, toni 는 기대 속성 name 이 없기 때문에 그렇지 않습니다.

결론

TypeScript는 정적 유형 정의를 추가하여 JavaScript를 확장하는 프로그래밍 언어입니다. 이를 통해 작업 데이터를 정의할 때 훨씬 더 정확하고 더 중요한 것은 오류를 더 일찍 감지하는 데 도움이 됩니다.

TypeScript를 개발 스택에 통합하는 비용은 비교적 적으며 점진적으로 수행할 수 있습니다. 모든 JavaScript 코드는 정의에 따라 TypeScript이므로 JavaScript에서 TypeScript로의 전환은 자동입니다. 한 번에 한 단계씩 유형을 추가하고 코드를 꾸밀 수 있습니다.

이 게시물이 마음에 들었고 더 자세히 알고 싶다면 공유하고 아래 댓글 섹션에 알려주십시오.

Unsplash에 대한 King's Church International의 특집 이미지.