/*
공식 문서: https://www.typescriptlang.org/tsconfig/
tsconfig.json 기본 내용
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"noImplicitAny": true, // any type이 'any' 입력 없이 검출될 때 에러 출력(선택)
"strictNullChecks": true // null, undefineㅇ에 이상한 조작시 에러 출력(선택)
}
}
이게 기본형태(IE 호환성 측면에서 무난함.)
target: js 버전 설정 (es5, es2016, esnext; 최신)
module: js 파일간 import 문법 설정 (commonjs: require, ex2015 이후: import)
자주 사용하는 것만 정리
{
"compilerOptions": {
"target": "es5", // 'es3', 'es5', 'es2015', 'es2016', 'es2017','es2018', 'esnext' 가능
"module": "commonjs", //무슨 import 문법 쓸건지 'commonjs', 'amd', 'es2015', 'esnext'
"allowJs": true, // js 파일들 ts에서 import해서 쓸 수 있는지
"checkJs": true, // 일반 js 파일에서도 에러체크 여부
"jsx": "preserve", // tsx 파일을 jsx로 어떻게 컴파일할 것인지 'preserve', 'react-native', 'react'
"declaration": true, //컴파일시 .d.ts 파일도 자동으로 함께생성 (현재쓰는 모든 타입이 정의된 파일)
"outFile": "./", //모든 ts파일을 js파일 하나로 컴파일해줌 (module이 none, amd, system일 때만 가능)
"outDir": "./", //js파일 아웃풋 경로바꾸기
"rootDir": "./", //루트경로 바꾸기 (js 파일 아웃풋 경로에 영향줌)
"removeComments": true, //컴파일시 주석제거
"strict": true, //strict 관련, noimplicit 어쩌구 관련 모드 전부 켜기
"noImplicitAny": true, //any타입 금지 여부
"strictNullChecks": true, //null, undefined 타입에 이상한 짓 할시 에러내기
"strictFunctionTypes": true, //함수파라미터 타입체크 강하게
"strictPropertyInitialization": true, //class constructor 작성시 타입체크 강하게
"noImplicitThis": true, //this 키워드가 any 타입일 경우 에러내기
"alwaysStrict": true, //자바스크립트 "use strict" 모드 켜기
"noUnusedLocals": true, //쓰지않는 지역변수 있으면 에러내기
"noUnusedParameters": true, //쓰지않는 파라미터 있으면 에러내기
"noImplicitReturns": true, //함수에서 return 빼먹으면 에러내기
"noFallthroughCasesInSwitch": true, //switch문 이상하면 에러내기
}
}
*/
// 터미널: tsc -w 입력시 자동변환(갱신)모드 작동 -> 켜놓고 ts에 개발하면서, 실제 파일 사용시 js만 사용
let 이름: string = 'kim';
let 어레이: string[] = ['kim', 'park'];
let 오브젝트: { name? : string } = { name : 'kim'}; // ?는 'undefined'도 가능하다는 의미(optional 느낌)
let 다양함: string[] | number = 123; // | = uniton type(다양한 type 허용)
// 커스텀 type(type alias) 만들기: 복잡한 type (특히 object)에 쓰임
type Custom = string | number; // custom type은 CamelCase
type FixedLastName = 'kim' | 'park'; // 이 경우 'kim', 'park'만 입력 가능
let 특수함: Custom = 123;
// 이미 만든거 위에있는데 또 재할당 불가 type Custom = number; (X)
type Member = { [key: string] : string} // key - object 둘다 string 으로 고정 (object 일괄 적용)
// custom type 합치기(= extend)도 가능
type Name = string;
type Age = number;
type NewOne = Name | Age;
// object 재활용해서 합치기
type PositionX = { x: number };
type PositionY = { y: number };
type XandY = PositionX & PositionY // { x : number, y : number }
let 좌표 :XandY = { x : 1, y : 2 } // { x : number, y : number }
// 합칠때 중복있으면 자동으로 제거되면서 합쳐짐. key가 같은데 type이 다른 경우 불가능을 표시하는 'never' type으로 아무것도 입력못받는 형태로 변경
// 타입문제 1
type Type1 = {color? : string, size : number, readonly position : number[]}
let 테스트용변수1 : Type1 = {size : 123, position : [1,2,3]}
// 타입문제 2
type Validation = {name: string, phone: number, email: string}
// 타입문제 3
type StrictValidation = Validation & {underage : boolean}
let 임시 = 123; // 사실 type 지정 일일이 안해도 자동으로 커서올리면 씌워진거 확인 가능 -> 간단한 변수는 타입 지정 생략하자
// 에러메세지는 실행중인 tsc -w 의 터미널에 출력됨
let 좋아하는거 :{ song : string, singer : string } = { song : 'ㅇㅇ', singer : 'ㅇㅎ' }
let project :{
member : string[],
days : number,
started : boolean,
} = {
member : ['kim', 'park'],
days : 30,
started : true,
}
let 여러타입어레이: (string|number)[] = [1, '2', 3];
let 여러타입obj: {a : string | number} = { a : '123'};
let 아무거나: any; // type 지정 해제 문법 -> 이것을 다른 곳에 할당하면 할당된 곳의 type 지정도 해제됨 -> type 지정 해제가 필요할때 사용하자
let 타입용아무거나: unknown // -> 그래서 any대신 unknown을 쓰면 그 변수만 unknown이고 다른 곳에 영향주지 않으니 좀 더 안정적
// 실질적으로는 any나 unknown은 남이 만든 코드 리뷰할 때 안되면 임시로 사용하는 용도
// 숫자연산의 경우 number만 가능 -> unknown, any, 또는 union에 number를 포함하더라도 연산 안됨
// let 나이: string|number;
// 나이 + 1;
// let 나이: unknown = 1;
// 나이 + 1;
let 학교: {
score: (number | boolean)[],
teacher: string,
friend: string | string[]
}
= {
score : [100, 97, 84],
teacher : 'Phil',
friend : 'John'
}
학교.score[4] = false;
학교.friend = ['Lee' , 학교.teacher]
// 함수
function 함수(x: number): number { // number -> number
return x * 2
}
// return이 없는 함수 타입지정
function 노리턴함수(x?: number): void { // JAVA, C#의 void 개념과 유사, 파라미터가 옵션인 경우에는 변수?: 타입형태로 입력
}
// x? 의미 -> x: number | undefined 로 정의하는 것과 같음
// union이나 ? 쓴 경우 아래의 함수 다 에러 표기 (엄격한 number가 아니기 때문 -> narrowing; type 조건이 맞으면 연산하도록 조건 설계 필요)
// function 자릿수세기(x :number | string){
// return x + 1
// }
// function 내함수(x? :number) :number {
// return x * 2
// }
//연습문제 1
function 안녕이름(name?: string): void {
name
? console.log(`안녕하세요 ${name}`)
: console.log("이름이 없습니다.");
// console.log(name ? `안녕하세요 ${name}` : "이름이 없습니다."); // 한 줄 코드
}
const 안녕이름2 = (name?: string) => console.log(name ? `안녕하세요 ${name}` : "이름이 없습니다."); // 화살표 함수 사용
안녕이름2()
// 연습문제 2
const 자릿수세기 = (input_data: number | string): number => String(input_data).length
function 자릿수세기2(x :number | string) :number {
return x.toString().length
}
/**연습문제 3
* 결혼 가능 확률을 알려주는 함수를 만들어봅시다.
1. 함수의 파라미터로 월소득(만원단위), 집보유여부(true/false), 매력점수 ('상' or '중' or '하') 를 입력할 수 있어야합니다.
2. 월소득은 만원 당 1점, 집보유시 500점 & 미보유시 0점, 매력점수는 '상'일 때만 100점으로 계산합니다.
3. 총 점수가 600점 이상일 경우 "결혼가능"을 return 해줘야합니다. 그 외엔 아무것도 return하지 않습니다.
*/
const 결혼가능하냐 = function(월소득: number, 집보유여부: boolean, 매력점수: '상' | '중' | '하'): string|null {
let incomeScore = Math.floor(월소득 / 10000);
let homeownershipStatus = 집보유여부? 500 : 0;
let attractiveness = (매력점수 === '상')? 100 : 0;
return (incomeScore + homeownershipStatus + attractiveness >= 600)? "결혼가능" : null;
};
const 결혼가능하냐1 = (월소득: number, 집보유여부: boolean, 매력점수: '상' | '중' | '하'): string | null => {
const score = Math.floor(월소득 / 10000) + (집보유여부 ? 500 : 0) + (매력점수 === '상' ? 100 : 0);
return score >= 600 ? "결혼가능" : null;
};
const 결혼가능하냐2 = (월소득: number, 집보유여부: boolean, 매력점수: '상' | '중' | '하'): string | null =>
Math.floor(월소득 / 10000) + (집보유여부 ? 500 : 0) + (매력점수 === '상' ? 100 : 0) >= 600 ? "결혼가능" : null;
// Narrowing: 여러 타입이 있는 것에 대해서는 type을 하나로 확정시켜야 코드 동작
if (typeof 다양함 === 'number') { // 이후 숫자 연산 가능
다양함 + 1 };
// 속성명 in obj자료 , 인스턴스 instanceof 부모 와 같은 검사로 narrowing도 가능
// assertion: 길어지는 if 대신 짧게 type 확정(여러 개 중 하나로 확정 가능하지만 이미 확정된걸 변경하는 용도는 아님!)
다양함 as number + 1 // 단 as는 해당 타입으로 100% 들어온다는 전제하에 사용해야 함 (그렇지 않다면 if문이 적절)
// -> as는 남이 짠 코드 수정할 때, 왜 에러나는지 모르겠을 때 비상용으로 주로 씀
// 연습문제 4
function 클리닝함수(데이터: (number | string)[]): number[] {
return 데이터.map((x: number | string): number => Number(x));
}
const 클리닝함수2 = (데이터: (number | string)[]): number[] => 데이터.map((x) => Number(x));
// 연습문제 5
const 담당과목 = (선생님: {'subject': string | string[]}): string =>
(typeof 선생님.subject === 'string') ? 선생님.subject : 선생님.subject[선생님.subject.length-1]
const 담당과목2 = (선생님: { subject: string | string[] }): string => {
const { subject } = 선생님;
return Array.isArray(subject) ? subject[subject.length - 1] : subject;
};
// readonly: 특정 속성 수정 못하게 에디터상에서 에러 출력시키기 -> readonly '대상'
type Girlfriend = {
readonly name : string,
}
let 여친 :Girlfriend = {
name : '엠버'
}
// 여친.name = '유라' //readonly라서 에러남
// 컴파일, 에디터 에러일 뿐 js는 잘 동작함. 에디터상에서만 빨갛게 만듦
// Literal Types: 특정 값만 입력받는 type -> 변수에 뭐가 들어오는지 엄격한 관리 + 자동완성 힌트 명료함
let 접니다: '대머리' | '솔로'
function 아무개함수(a : 'hello'): 0 | 1 { return 1} // a는 'hello'만 입력받고 return도 0과 1만 가능
function 가위바위보(뭐낼까: '가위' | '바위' | '보'): '가위'|'바위'|'보' {return '가위'};
// 이건 왜 그럴까? (Literal type의 문제점)
var 자료 = {name : 'kim'} as const
자료.name // 'kim'
function 이상해(a:'kim'){}
// 이상해(자료.name) // 에러출력! -> 함수는 'kim'이라는 type을 요구하는데 자료.name은 string type의 'kim'을 넣었기 때문
// 대응법: var 자료에 대한 type을 제대로 {name : string} 으로 하던가 자료.name as 'kim' 하던가 아니면 object 끝에 'as const' (= literal type 지정 알아서 하기)쓰던가
// as const의 효과: 포괄적 자동 type이 아닌 value 자체를 type으로 만듦 + object안의 모든 속성에 readonly로 적용
// 함수 형태를 type으로 만들고 사용하려면?
type NumOut = (x : number, y : number ) => number ; // 함수 type 지정은 arrow function만 되고 변수명 지정 필수임
let 하암수 :NumOut = function(x,y){return x + y} // 함수 type을 쓰려면 함수 표현식/화살표함수 형태로 작성해야 쓸 수 있음 <-> function 함수() 이건 '함수 선언식'
// 함수 type 연습문제1
let 회원정보: {
name : string,
age : number,
plusOne: (x: number) => number,
changeName: () => void
}
= {
name : 'kim',
age : 30,
plusOne (x){
return x + 1
},
changeName : () => {
console.log('안녕')
}
}
// 함수 type 연습문제2
type fuc1 = (input_data: string) => string
type fuc2 = (input_data: string) => number
const cutZero: fuc1 = function(input_data) {
return (input_data[0]) === '0'? input_data.slice(1) : input_data
}
const removeDash: fuc2 = (input_data) => Number(input_data.replace(/-/g, ''))
// 함수 type 연습문제3
function 만들함수(a: string, func1: fuc1, func2: fuc2){
let result = func1(a);
let result2 = func2(result);
console.log(result2)
}
만들함수('010-1111-2222', cutZero, removeDash) //1011112222 출력잘됨
// 클래스
class Person {
name; // 미리 변수 만들어야 constructor에서 this.name 사용 가능
constructor(name :string){
this.name = name;
}
}
/*
(index.html)
<h4 id="title">안녕하세요</h4>
<a href="naver.com">링크</a>
<button id="button">버튼</button>
<script src="변환된 자바스크립트파일.js"></script>
에 대해서 TS로 HTML 조작하기
*/
// h4 바꾸기
let 제목 = document.querySelector('#title');
// 제목.innerHTML = '반가워요' // 이렇게 쓰면 에러 -> 제목: Element | null 임 -> narrowing
if (제목 != null) {제목.innerHTML = '반가워요'} // 방법 1
if (제목 instanceof Element) (제목.innerHTML = '반가워요') // 방법 2 (가장 권장되는 방법)
if (제목?.innerHTML != undefined) {제목.innerHTML = '반가워요'} // 방법 3
/*
html 태그 종류별로 정확한 타입명칭이 있습니다.
a 태그는 HTMLAnchorElement
img 태그는 HTMLImageElement
h4 태그는 HTMLHeadingElement
..
백만개가 있는데 이런 정확한 타입으로 narrowing 해주셔야 html 속성 수정을 제대로할 수 있습니다.
전부 외울 필요는 없고 자동완성 잘 될걸요
*/
let 링크 = document.querySelector('#link');
if (링크 instanceof HTMLAnchorElement) {
링크.href = 'https://kakao.com' //잘됨
}
let 버튼 = document.getElementById('button');
if (버튼 instanceof HTMLAnchorElement) {
버튼.addEventListener('click', function(){
console.log('안녕')
})
}
// eventlistener는 이게 더 나음
let 버튼1 = document.getElementById('button');
버튼1?.addEventListener('click', function(){
console.log('안녕')
})
class Person {
name : string // this.name 전에 여기서 타입 지정해줘야 함 (또는 name;)
constructor(a: string){ // return 타입지정 불필요
this.name = a
}
func(){
console.log("함수" + this.name)
}
}
// class에 무언가 입력값을 만드려면 -> constructor로 만듦
let p1 = new Person('kim');
console.log(p1.func())
class Car{
model: string
price: number
constructor(model: string, price: number){
this.model = model;
this.price = price;
}
tax(){
return (this.price/10)
}
}
let car1 = new Car('소나타', 3000)
console.log(car1) //콘솔창 출력결과는 { model : '소나타', price : 3000 }
console.log(car1.tax()) //콘솔창 출력결과는 300
class Word {
num: number[] = [];
str: string[] = [];
constructor(...inputData: (number | string)[]) {
for (const item of inputData) {
if (typeof item === 'number') {
this.num.push(item);
} else {
this.str.push(item);
}
}
}
}
let obj = new Word('kim', 3, 5, 'park');
console.log(obj.num) //[3,5]
console.log(obj.str) //['kim', 'park']
//-----------------------------------------
// interface명: 영문대문자로 시작
interface Square { color: string, width: number}
let sq: Square = {color : 'red', width: 100}
interface St {name: string}
interface Tch extends St {age: number} // type 방식))) type Tch = St & {age: number}
// 사실 interface도 extend없이 개별값만해서 let variable: St & Tch = {~} 로도 됨
let stu: St = {name : 'kim'}
let tchr: Tch = {name: 'kim', age: 20}
// 주요 차이점: type은 중복선언(재선언) 불가, interface는 가능(내용이 다르면 자동으로 extends처럼 반영해줌)
// -> 다른 사람이 나의 코드를 사용하는 경우가 많다면 유연한 interface 사용이 적절 (type은 엄격한 정의 용)
interface Goods {brand: string, serialNumber: number, model: string[]}
interface Cart {product: string, price: number}
interface SpCart extends Cart {card: boolean}
interface p {plus: (a: number, b: number) => number, minus: (a: number, b: number) => number}
const objp: p = {
plus: (a, b) => a+b,
minus: (a, b) => a-b
}
const maxNum = (...nums: number[]) => {
let maxVal = nums[0];
for (let i = 1; i < nums.length; i++ ) {
if (nums[i] > nums[0]) maxVal = nums[i]
}
return maxVal
}
const desfunc = ({user, comment, admin}: {user: string, comment: number[], admin: boolean}) => {
return {user, comment, admin}
}
console.log(desfunc( { user : 'kim', comment : [3,5,4], admin : false } ) )
type 어레이 = (number | string | boolean)[];
function 함수([a,b,c]:어레이){
console.log(a,b,c)
}
함수( [40, 'wine', false] ) // array destructuring할 때는 자유작명이 가능
type Fish = { swim: string };
type Bird = { fly: string };
function 함수(animal: Fish | Bird) {
if ("swim" in animal) { // 파라미터 unique 속성으로 narrowing
return animal.swim
}
return animal.fly
}
// obj instanceof 부모 클래스 구조로도 narrowing 가능
let date = new Date();
if (date instanceof Date) {
}
// 특정 고정값 = literal type -> narrowing 근거로 사용 가능
type Cars = {wheel: 4, color: string}
type Bike = {wheel: 2, color: string}
function chkfunc(x: Cars | Bike){
}
// never type: 1. 무언가 return 하지 않고 2. 끝나지도 않는(endpoint 없음) 함수를 표현하고 싶을 때 never type
// 2번 조건의 함수를 만들 일이 거의 없기 때문에 never 타입은 쓸 일이 없음 -> 무언가를 return하고싶지 않을 경우 그냥 void 쓰면되므로 굳이 never 쓸 필요 없음
// -> never는 코드 이상하게 짜다보면 자동 등장하므로 이때 그 의미 파악, 즉 모순적이거나 문제가 있을 때 등장
// function 함수() :never{
// while ( true ) {
// console.log(123)
// }
// }
// function 함수() :never{
// throw new Error('에러메세지')
// }
// 함수 파라미터가 never
function weirdFunc(parameter: string) {
if ( typeof parameter === "string"){
parameter + 1;
} else {
parameter; // 이게 never
}
}
// 즉, never가 보이면 뭔가 코드가 이상하거나 모순적이란 의미
function 함수1(){ // return void
throw new Error()
}
let 함수2 = function (){ // 이 경우 return이 never
throw new Error()
}
// 그외 strict로 any 할당 불가시 never
// public(없는 기존의 형태가 public), private(해당 클래스 안에서만 동작 및 수정이 가능하면서 외부의 new 형태로 수정 불가능하도록 할 때)
// class User {
// name;
// constructor(){ // 파라미터 입력할 수 있도록 해줌
// this.name = 'kim'
// }
// }
class User {
constructor(public name: string){ // name;, this.name=name 없이 public으로 먼저 선언하여 이 과정 생략 가능
}
}
// protected: private보다 약간 느슨한(상속된 class에서도 조작가능) 형태
// static: class 안의 간단한 메모 / 기본 설정 값 입력 / class 부산물 obj가 사용할 필요가 없는 경우에 사용
// static은 private, protected, public과 같이 쓸 수 있음
class Users {
static skill = 'js';
intro = Users.skill + '전문가입니다' // static은 원본 클래스를 호출해야함(this.skill 안됨)
}
var 철수 = new Users();
console.log(철수);
Users.skill = 'python'; // static은 원본 클래스를 호출한 경우 값 수정도 가능
var 민수 = new Users();
console.log(민수);
//__________________________________________________________________________________
class Users1 { // 누가 어디서 쓸 수 있음?
private static x = 10; // Users1안에서 User1만 가능
public static y = 20; // 외부/내부 상관없이 Users1만 가능
protected z = 30; // Users1 및 상속된 클래스들에 대해서 Users1만 가능
}
class Users2 {
private static x = 10;
public static y = 20;
static addOne(num: number){return num + Users2.x}
static printX(){console.log(Users2.x)}
}
Users2.addOne(3) //이렇게 하면 x가 3 더해져야함
Users2.addOne(4) //이렇게 하면 x가 4 더해져야함
Users2.printX() //이렇게 하면 콘솔창에 x값이 출력되어야함
// let 네모 = new Square(30, 30, 'red');
// 네모.draw()
// 네모.draw()
// 네모.draw()
// 네모.draw()
// __________________________________________________
// type도 import, export 가능
//(a.ts)
//export type Name = string | boolean;
//export type Age = (a :number) => number;
//(b.ts)
//import {Name, Age} from './a'
//let 이름 :Name = 'kim';
//let 함수 :Age = (a) => { return a + 10 }
// 옛날 import, export 없었을 때의 문법
//(a.ts)
namespace MyNamespace { // 이걸로 감싸서 export. 더 과거의 문법은 module MyNamespce
export interface PersonInterface { age : number };
export type NameType = number | string;
}
// (b.ts)
// 옛날 방식의 import
/// <reference path="./a.ts" />
let 이름 :MyNamespace.NameType = '민수'; // 그냥 NameType이 아니라 MyNameSpace의 NameType이다.
let 나이 :MyNamespace.PersonInterface = { age : 10 };
type NameType = boolean; // 위의 것과 별도의 의미로 사용 가능
interface PersonInterface {} // 위의 것과 별도의 의미로 사용 가능
// type문제1) export {type Car, interface Bike} 후 import {type Car, interface Bike}
// type문제2)
// const tempFunc = (inputData:specificType) => {
// }
// type문제3)
namespace StrTy {export type Dog = string;}
interface Dog { name : string };
let dog1: StrTy.Dog = "bark";
// generic func: type을 함수 파라미터처럼 가변적으로 입력하기, 보통 변수명 <T>로 사용
function 함수<MyType>(x: MyType[]) :MyType {
return x[0];
}
// MyType에 입력에 따라 달라지는 type 적용
let ka = 함수<number>([4,2])
let kb = 함수<string>(['kim', 'park'])
// myType에 입력될 type 제한하기: extends로 제한
function 함수1<MyType extends number>(x: MyType){
return x - 1
}
// 연습1) 문자를 집어넣으면 문자의 갯수, array를 집어넣으면 array안의 자료 갯수를 콘솔창에 출력해주는 함수
const CountingNum = <MyType extends string | []>(x: MyType):number => {
return x.length
}
// 연습2)
interface Animal {
name : string;
age : number
}
let data = '{"name" : "dog", "age" : 1 }'
function pj<T extends Animal>(x: T):T {
return JSON.parse(data)
}
// 연습3) class 수정
class Person<T>{ // type 구멍
name;
constructor(a: T) { // 생성자함수는 입력부분만 가능.
this.name = a;
}
}
let a = new Person('어쩌구');
a.name //any -> string
// array안에 string[] 그 이상으로 구체적으로 타입 지정 -> [] 안에 type 적는 형태(tuple)
let 멍멍이 :[string, boolean?, number?]; // ? : optional
멍멍이 = ['dog', true]
// spread에 type 붙이기
let arr = [1,2,3]
let arr2 :[number, number, ...number[]] = [4,5, ...arr]
// 문2)
let arr3: [string, number, ...boolean[]] = ['동서녹차', 4000, true, false, true, true, false, true]
// 문3)
const tupFunc = (...x:[string, boolean, ...(string|number)[]]) => {}
// 문4)
const classify = (...x: (string|number)[]): [string[], number[]] => {
const str: string[] = [];
const num: number[] = [];
for (let data of x) {
typeof data === "string"? str.push(data): num.push(data);}
return [str, num]
}
console.log(classify('b', 5, 6, 8, 'a')) // [ ['b', 'a'], [5, 6, 8] ]
// ts로 작성되지않은 js의 변수/함수 등을 호출할 때
declare let 외부변수: number; // 이렇게 사용. 디렉토리 어딘가에 정의되어있으니 그거 쓰라는 의미
// ambient module: ts는 import,export없이 전역적으로 다른파일에 선언된것 바로 사용 가능
// -> 이것을 막으려면 tsconfig.json에 "moduleDetection": "force" 설정 또는 각 파일마다 export {} 구문 추가(export내용 없어도 됨)
// 이렇게 제한된 상태에서 global 변수/타입 만드려면?
declare global {
type Dog = string;
}
// d.ts 의 의미? -> 타입 정의(type, interface) 보관용 파일들 -
// --> import { ~} from './~.d.ts';
// tsconfig.json에 "declaration": true 로 하면 ~d.ts 자동 생성 -> 굳이 수정 안해도 됨. 단 자동 global module 아님
// d.ts global화하려면 "typeRoots": ["./types/common/"] 근데 이거 쓰면 자동 type 반영 막힘
// 외부 라이브러리의 type(JQuery) import -> ts 공홈의 type search로 설치
// 특정 클래스가 interface의 type을 모두 포함하고 있는지 여부를 검사 -> implements 인터페이스타입
interface CarType {
model : string,
price : number
}
class Car implements CarType { // 문제있으면 오류 발생시켜줌. 타입 속성 확인만 하므로 타입 할당/변형 의미 아님
model : string;
price : number = 1000;
constructor(a :string){
this.model = a
}
}
let 붕붕이 = new Car('morning');
// -> 즉 implements는 복잡한 여러 class에서 확인이 필요할 때에 사용
// interface 한번에 type 지정 -> index signature
interface StringOnly {
[key: string]: string // 모든 키값의 value는 string이다.(한번에 지정)
}
let obj1 :StringOnly = {
name : 'kim',
age : '20',
location : 'seoul'
}
// 길어진 재귀구조 한번에 type 지정하기
interface MyType { // type도 재귀로 구성함
'font-size': MyType | number
}
let obj3: MyType = {
'font-size' : {
'font-size' : {
'font-size' : 14
}
}
}
// 문1: interface MyT { [key: string]: string | number}
// 문2:
interface RecurT {
'font-size': number,
[key: string]: RecurT | number
}
let obj2: RecurT = {
'font-size' : 10,
'secondary' : {
'font-size' : 12,
'third' : {
'font-size' : 14
}
}
}
// keyof: object의 모든 key의 값을 union으로 합쳐서 출력
interface Person1 {
age: number;
name: string;
}
type PersonKeys1 = keyof Person1; // === age | name
interface Person2 {
[key :string]: number;
}
type PersonKeys2 = keyof Person2; // === string | number (key값에 number넣어도 자동 String되기 때문)
// 타입 변환기: type 수정을 수동으로 하지않고 코드로 한 번에 하기
type Car1 = {
color: boolean,
model : boolean,
price : boolean | number,
};
type TypeChanger<T> = {
[key in keyof T]: string
}
type Car2 = TypeChanger<Car1> // Car2로 새로 생성 (모두 string type으로 일괄 변환 = 매핑)
// 세부적으로 특정 key는 다르게 -> 삼항 조건문 이용해서 조정
type Bus = {
color : string,
model : boolean,
price : number
}
type TypeChanger2<T> = {
[key in keyof T]: string | number
}
type Bus2 = TypeChanger2<Bus>
type TypeChanger3<MyT, T> = {
[key in keyof MyT]: T
}
type Bus3 = TypeChanger3<Bus, string[]> // 입력한 값으로 반영하는 유연한 형태
type Age<T> = T extends string? T: unknown; // T 파라미터 조건문 검사는 extends로 수행
// T가 string이면 T, 아니면 unknown
let newA: Age<number> // string 아니라서 unknown됨
type FirstItem<T> = T extends []? T[0]: any // array오면 array의 첫번째 원소 타입을, 나머지는 any로
// 조건문에 쓸 수 있는 infer (자주 쓰진 않지만 읽을 줄은 알아야)
// infer = 왼쪽에서 type 정보를 추출해서 '변수;R'에 담아주세요 -> 그렇게 담아서 활용할 때 씀
type ExtractionT<T> = T extends (infer R)[] ? R : unknown
type ext = ExtractionT<string[]> // array의 내부 type만 추출
type ExtractionT2<T> = T extends (() => infer R) ? R : unknown
type ext2 = ExtractionT2<() => void> // 함수 return type만 추출
// 사실 이건 ReturnType<함수> 에 넣으면 return의 type만 추출하는 것과 동일함
type ext3 = ReturnType<() => void> // void
// 1. array 타입을 <> 안에 입력하면 array 타입의 0번째 타입이 string이면 string 타입을 그대로 남겨주고 array 타입의 0번째 타입이 string이 아니면 unknown 을 남겨주려면 어떻게 타입을 만들어놔야할까요?
type condT<T> = T extends [string, ...any]? T[0] : unknown
// 2. 함수 파라미터 추출
type extT<T> = T extends (x: infer R) => {}? R : unknown728x90
반응형
'Programming > JavaScript' 카테고리의 다른 글
| [TS] 기본 세팅 (1) | 2026.05.15 |
|---|---|
| Optional chaining, Nullish coalescing operator (0) | 2026.05.15 |
| get/set, destructuing, Promise, async/await, for of, Symbol, Map, Set, customHTML (0) | 2026.05.14 |
| Promise 추가 내용 (0) | 2026.05.13 |
| this, arrow fucntion, template literals, tagged literals, spread operator, rest 파라미터, apply, call, Class, extends (1) | 2026.05.12 |