Lsiron
Type Script 함수 타입 지정 ( Narrowing, Assertion, alias + object randomly ) 본문
Type Script 함수 타입 지정 ( Narrowing, Assertion, alias + object randomly )
Lsiron 2024. 7. 8. 02:39함수에 타입을 지정할 때.
function test(x:number):number {
return x * 2
}
test(2) // 4
parameter와 return 값에 타입 지정이 가능하다.
단, return 값에 타입을 지정할 땐 리턴 값 옆이 아니라 파라미터 소괄호 오른쪽에 해준다.
만약 파라미터에 타입을 지정하지 않을 시, any 타입이 할당된다.
즉, 위 test함수는 무조건 number가 들어와야하며, return 값은 무조건 number가 반환돼야한다.
자바스크립트 함수와 다른 점은 타입 지정된 파라미터는 필수로 파라미터를 넣어줘야한다.
function test(x) {
return x * 2
}
test()
기존 자바스크립트는 위와 같이 파라미터를 집어넣지 않고 test() 이런 방식으로 사용 할 수 있었다.
허나 타입스크립트는 파라미터에 타입을 지정 해 준이상 값을 test(2) 와 같이 값을 반드시 넣어주어야 한다.
넣어주지 않으면 에러가 발생한다.
만약 parameter 값이 있든 없든 오류가 발생하지 않도록 하고 싶다면 아래와 같이 파라미터를 작성하면 된다.
function test(x?:number):number {
return x * 2
}
test() // 오류 발생 X
이렇게 '?' 를 파라미터 우측에 써주면 파라미터를 집어넣지 않아도 에러가 발생하지 않는다.
참고로 object 자료를 만들때 키 값에도 '?' 를 넣어 줄 수 있다.
{ age? : number }
키 값이 들어 올 수도 있고 안 들어 올 수도 있다는 뜻이다.
'?' 연산자는 들어올 수도 있다 라는 뜻인데 정확한 뜻은 undefined와 똑같다. (★)
다시말해서, 변수?:number 는 변수:number | undefined와 같다는 말 이다.
void 타입
함수에서만 사용할 수 있는 특별한 타입이 있다. 바로 void 타입이다.
함수값을 return 하고 싶지 않을 때가 있다.
의도와는 다르게 return 값을 반환 할 때 오류가 나도록 하는 타입이 바로 void 타입이다.
function test(x:number):void {
1 + 1
}
아래와 같은 용도로 주로 사용된다.
1) 함수의 반환 타입: void 타입은 함수가 값을 반환하지 않을 때 사용된다. 예를 들어, 콘솔에 메시지를 출력하는 함수는 아무 값도 반환하지 않으므로 void 타입으로 정의할 수 있다.
function logMessage(message: string): void {
console.log(message);
}
2) 콜백 함수: 콜백 함수의 반환 값이 필요 없는 경우 void를 사용하여 반환 타입을 명시할 수 있다.
function performTask(callback: () => void): void {
// ...작업 수행
callback();
}
3) Promise 반환 함수: 비동기 작업을 수행하는 함수에서 반환하는 Promise가 어떤 값을 반환하지 않을 때 Promise<void>를 사용할 수 있다.
async function fetchData(): Promise<void> {
await fetch('https://example.com/data');
}
4) 타입 매개변수에서의 사용: void 타입은 제네릭 함수에서 타입 매개변수로 사용할 수 있다. 예를 들어, 콜백 함수가 아무 것도 반환하지 않는다는 것을 나타낼 때 사용할 수 있다.
async function fetchData(): Promise<void> {
await fetch('https://example.com/data');
}
5) 메서드 정의에서의 사용: 클래스나 인터페이스의 메서드가 값을 반환하지 않을 때 void를 사용할 수 있다.
interface Task {
execute(): void;
}
class MyTask implements Task {
execute(): void {
console.log('Task executed');
}
}
Type Narrowing
function test(x:number | string){
return x + 1
}
일반적으로 위와 같이 union type으로 파라미터에 타입을 할당 해 줄 경우, 수학연산을 적용하면 에러가 난다.
때문에 이렇게 Type이 하나로 확정되지 않았을 경우 아래와 같이 Type Narrowing을 사용해야한다.
function test(x:number|string){
if(typeof x === 'string'){
return x + '1'
} else {
return x + 1
}
}
특별한 것은 없다 그냥 if 조건문을 사용해서 타입이 number 아닌 것 일 경우를 설정해주면 된다.
예시를 하나 더 들어보자.
아래와 같이 number로 이루어진 배열에 union type으로 타입을 할당한 파라미터를 넣으면 에러가 발생한다.
function test(x:number|string){
let arr:number[] = [];
arr[0] = x;
}
이 경우 똑같이 Type Narrowing을 사용하면 된다.
function test(x:number|string){
let arr:number[] = [];
if (typeof x === 'number'){
arr[0] = x;
} else {
}
}
x 의 타입이 number 일 경우에만 배열에 넣어주도록 하면 된다.
주의점은 else나 else if를 꼭 넣어주도록 하자. 즉, if문을 사용했으면 끝까지 써주자.
그러지 않을 시 에러가 발생할 수 있다.
이 외에도 Narrowing으로 판정해주는 문법들이 있지만, 현재 변수의 타입이 무엇인지 특정지을 수만 있다면 다 인정해준다.
Narrowing을 통해 타입을 하나로 확정할 때, 내가 지정한 타입중에 null이나 undefined가 있다면?
&& 연산자로 타입을 Narrowing 할 수 있다.( 보통 null 과 undefined 타입체크를 하는 경우가 매우 잦다. )
if (변수 && typeof strs === "string") {}
&& 논리연산자로 비교할 때 true와 false를 넣는게 아니라 자료형을 넣으면 && 사이에서 처음 등장하는 falsy 값을 찾아주고 그게 아니면 마지막 값을 남겨준다.
falsy 값은 false와 유사한 기능을 하는 null, undefined, NaN 값들을 의미한다.
이 조건식은 변수의 값이 null 또는 undefined가 아닌지 확인하면서, 동시에 그 값이 문자열인지 확인한다. 이 방식은 주로 다음과 같은 상황에서 사용된다.
- 변수의 타입이 문자열인지 확인하고 싶을 때
- 변수의 값이 falsy 값(null, undefined, 0, NaN, "", false) 중 어느 것도 아니어야 할 때
이 방식의 장점은 한 번에 여러 조건을 확인할 수 있다는 점이다. 하지만 이 방식은 문자열이 아니면서도 truthy한 값(1, true, 객체 등)도 통과시킨다는 단점이 있다.
변수의 값이 null 또는 undefined 가 아닌지 확인하는 방법이 하나 더 있다.
if(변수 != null)
이 조건식은 변수의 값이 null 또는 undefined가 아닌지 확인한다. 이 방식은 주로 다음과 같은 상황에서 사용된다.
- 변수의 존재 여부만 확인하고 싶을 때
- 변수의 타입이 특정 타입이어야 하는 것이 아니라 단순히 null이나 undefined가 아닌지만 확인하면 될 때
이 방식의 장점은 간단하고, 코드가 명확하며, 모든 falsy 값을 고려하지 않고 오직 null과 undefined만 검사한다는 점이다.
현업에서 둘 중 어떤 조건식을 더 많이 사용하는지는 코드의 문맥과 팀의 코딩 스타일 가이드에 따라 다를 수 있다. 하지만 일반적으로
- 특정 타입(예: 문자열)인지 확인이 필요하다면 첫 번째 방식을 사용할 것이다.
- 단순히 null이나 undefined가 아닌지만 확인할 때는 두 번째 방식이 더 많이 사용된다.
in 연산자로 Object 자료를 narrowing 할 수 있다 ?
타입스크립트에서 in 연산자를 사용하여 객체에 특정 키가 존재하는지 확인하는 방법도 Narrowing 효과를 얻을 수 있다.
예를 들어, 다음과 같은 유니언 타입을 가지는 객체가 있다고 가정해 보자.
type User = {
name: string;
age?: number;
};
type Admin = {
name: string;
privileges: string;
};
위의 코드에서 Admin 타입에는 privileges라는 키가 존재하고, User 타입에는 존재하지 않는다.
이제 in 연산자를 사용하여 객체가 Admin 타입인지 확인하고 타입을 좁히는 예제를 살펴보자.
function personInfo(person: User | Admin) {
if ('privileges' in person) {
// person 타입은 Admin으로 좁혀졌다.
console.log(`${person.name} 는 ${person.privileges} 권한을 가진 admin 이다.`);
} else {
// person 타입은 User로 좁혀졌다.
console.log(`${person.name} 은 user 이다.`);
if (person.age !== undefined) {
console.log(`Age: ${person.age}`);
}
}
}
const admin: Admin = {
name: "Alice",
privileges: "manage-users"
};
const user: User = {
name: "Bob",
age: 30
};
personInfo(admin); // Alice 는 manage-users 권한을 가진 admin 이다.
personInfo(user); // Bob 은 user 이다. Age: 30
Admin은 name과 privileges, User는 name과 age 처럼 서로 배타적인 속성을 가져와야 narrowing이 가능하다.
class로부터 생산된 object라면 instanceof로 narrowing
어떤 클래스로부터 new 키워드로 생산된 object 들은 instanceof 키워드를 붙여서 부모 클래스가 누군지 검사할 수 있는데,
이것도 narrowing 역할을 할 수 있다.
자바스크립트에선 new Date() 를 사용하면 date object 가 생성된다. 그래서 간단하게 이를 예시로 instanceof 를 사용하여 부모 클래스가 누군지 검사할 수 있다.
let 날짜 = new Date();
if (날짜 instanceof Date){
console.log('참')
}
이런 문법도 narrowing 역할을 할 수 있다. 이 변수가 Date()로 부터 생성된 object 자료인지, 아니면 다른 object로부터 생성된 자료인지 구분가능하기 때문이다.
object들 구분할 일이 많을 때 literal type을 만들어두면 편리한데, literal type이 있으면 narrowing 쉬워진다.
type Car = {
wheel : '4개',
color : string
}
type Bike = {
wheel : '2개',
color : string
}
function 함수(x : Car | Bike){
// 타입이 Car으로 좁혀졌다.
if (x.wheel === '4개'){
console.log('the car is ' + x.color)
// 타입이 Bike로 좁혀졌다.
} else {
console.log('the bike is ' + x.color)
}
}
비슷한 object 자료를 많이 다룰 땐, literal type으로 object 안에 각각 유니크한 자료를 달아두면 나중에 구분하기 편리할 수 있다.
Assertion ( 잘 사용하지 않음 - 디버깅용으로 가끔 사용함 )
Narrowing 문법 말고도 타입을 하나로 확정 지을 수 있는 문법이 있는데 바로 Assertion이다.
이 assertion은 쉽게 말해서 타입을 덮어씌우는 문법이다.
예시를 통해 알아보자.
function test(x:number|string){
let arr:number[] = [];
arr[0] = x
}
기존에 위 문법은 x 의 타입이 하나로 확정되지 않아서 오류가 났고 이를 if 조건문을 통해 Narrowing 을 해주어, 타입을 확정지었다.
허나 if 조건문을 안 써도 되는 Assertion을 사용해보자.
function test(x:number|string){
let arr:number[] = [];
arr[0] = x as number;
}
바로 x 우측에 as를 써주고 그 다음으로 타입을 써주면 된다. 즉, x의 타입을 number로 덮어달라는 말 이다.
허나 Narrowing 할 때 Assertion이 편하다고 해서 Assertion만 사용하면 안된다.
Assertion은 타입을 확정 지을 때 사용하는 문법이지, 타입을 a에서 b로 변경하는 용도로 사용하는 것이 아니다.
assertion 문법의 용도를 한번 알아보자.
1. Narrowing 할 때 사용.
2. 어떤 타입이 틀어올지 100% 확실할 때 사용.
function test(x:number|string){
let arr:number[] = [];
arr[0] = x as number;
}
test('123')
위 처럼 as 문법을 사용해서 number로 덮어주었더라도 함수 파라미터에 문자열을 넣어도 에러가 발생하지 않는다.
즉, 버그 발생한다.
Type alias
타입이 너무 길고 복잡하면 변수에 담아서 사용할 수 있다.
type Mine = string | number;
let age:Mine = 28;
위와 같이 타입을 변수에 담아서 사용 가능하다. 타입명은 보통 대문자로 시작하도록 작명한다.
특히 object에서 많이 사용한다.
type Siron = {name : string, age : number }
let lsiron :Siron = { name : 'Lee', age : 28}
또한, Type 변수도 union type으로 합치는 방식이 가능하다.
type Name = string;
type Age = number;
type Person = Name | Age;
마지막으로 & 연산자로 object 타입을 합치는 방식도 가능하다. ( object extend )
type PositionX = { x : number };
type PositionY = { y : number };
type NewType = PositionX & PositionY; // { x : number , y : number}
type alias 에 함수 type 저장해서 쓰는 방법
type alias에 함수 type을 저장해서 사용할 때는 반드시 type 함수를 애로우 함수로 작성 해야한다.
또한 함수 type alias를 적용하려면 함수표현식을 사용해야한다.
// 타입 지정을 할 땐 반드시 애로우함수를 사용해야한다.
type siron = (x:string) => number;
let lsiron:siron = function (x){
return 10
}
위 함수 타입에는 무조건 string 타입을 집어 넣을 수 있고 결과는 무조건 number 타입을 배출한다.
1. object 안에 함수 만들기
type Lsiron = {
name : string,
age : number,
cal : ( x :number ) => number,
changeName : () => void
}
let iron:Lsiron = {
name : 'ron',
age : 28,
cal : (x) => {
return x + 1
},
changeName : () => {
}
}
//object 내부 함수 사용방법
iron.cal(2) // 3 출력
Object의 Readonly 속성
자바스크립트 const 변수에서 object의 value 값은 바꿀 수 있다. 재할당만 되지 않는 것.
const siron = { name : 'lsiron'}
siron.name = 'iron'
즉, 위와 같이 value 값을 변경하는 것은 가능하다.
허나, 타입스크립트 에서는 이러한 object의 자료가 수정되는 것을 막을 수 있다.
type Ls = {
readonly name : string
}
const siron:Ls = {
name : 'lsiron'
}
siron.name = 'iron' // 에러발생
바로 위 처럼 object 타입을 선언 할 때, 키 값에 readonly를 붙여주면 에러가 발생한다.
즉, value 값 수정이 되지 않도록 해주는 것 이다.
명심해야 할 것은 타입스크립트 에러는 실행을 막아주는 것이 아니라, 에디터 혹은 터미널에만 존재하고, 변환된 자바스크립트 파일에서는 똑같이 바꿔준다.
또한, 같은 이름의 Type 변수는 재정의가 불가능하다. ( 자바스크립트의 const 변수처럼 )
type Siron = number ;
type Siron = string ; // 에러발생 !!
참조 : 코딩애플
'언어 > Type Script' 카테고리의 다른 글
Type Script 함수 타입 지정 심화(rest parameter, destructing, never) (1) | 2024.07.14 |
---|---|
Type Script로 Class와 prototype에 타입지정하기(interface) (0) | 2024.07.12 |
Type Script로 HTML 변경과 조작 (instanceof, optional chaining) (2) | 2024.07.12 |
TypeScript로 변수에 타입을 지정할때 (0) | 2024.07.06 |
Typescript란? 그리고 TypeScript 설치방법 (0) | 2024.07.06 |