2020. 2. 29. 00:13ㆍtypescript/typescript-grammar
변수 선언
let과 const는 js에서 상대적으로 새로나온 변수 선언 방법입니다. let은 var과 비슷하지만 재선언 등을 사용하지 못합니다. 그리고 const는 한번 적용한 값을 변환시킬 수 없는 변순 선언 법입니다.
typescript는 js를 포함하고 있기 때문에 당연하게 let, const를 사용할 수 있습니다. 그래서 과거의 var를 사용하는 것 보단 let과
const를 사용하는 것이 더 바람직합니다.
let
var의 몇가지 문제 점들을 해결한 변수선언 방법이다. let은 var와 같은 방법으로 선언하여 사용할 수 있다.
let hello = "Hello!";
block scope
var는 function scope라서 함수를 기준으로 변수를 찾아와 사용하지만 let은 block scope {}을 기준으로 변수를 찾을 수 있습니다.
let의 경우
function f(input: boolean) {
let a = 100;
if (input) {
let b = a + 1;
return b;
}
return b; Error // 다른 블록에 있어서 if 안에 들어있는 b를 반환하지 못한다.
}
var의 경우
function f(input: boolean) {
let a = 100;
if (input) {
var b = a + 1;
return b;
}
return b; // var는 함수를 기준으로 scope를 구성하기 때문에
} // 에러가 발생하지 않는다.
또한 let고 const는 호이스팅이 안된다. 따라서 아래와 같은 구문은 되지 않는다.
x++;
let x = 1;
아래와 같은 경우 ES2015이후로는 원래 에러가 발생해야하지만 지금 당장의 typescript에서는 에러가 발생하지 않습니다.
function foo() {
// okay to capture 'a'
return a;
}
// foo를 호출해주기 전에 a를 선언하는 것은
// 에러가 발생할 것입니다.
foo();
let a;
재선언
var의 경우 재선언을 해주어도 특별한 에러가 생기지 않았다. 아래와 같이 var의 경우에는 재선언을 허용한다.
function f2(x) {
var x;
var x;
if (true) {
var x;
}
}
하지만 let의 경우 아래와 같이 작성할 경우 에러가 발생한다.
let x = 10;
let x = 20;
또는 아래와 같은 경우에도 에러가 발생한다.
function f(x){
let x = 100;
}
function g(){
var x = 1;
let x = 2; Error
}
그리고 아래와 같은 경우에 block을 다르게 scope를 구성하기 때문에
function f3(condition, x) {
if (condition) {
let x = 100;
return x;
}
return x;
}
f3(true, 0); // return 100
f3(false, 0); // return 0
Shadowing
shadowing은 우발적으로 에러를 발생시키기도 하고 예방시켜 주기도 합니다. 그래서 양날의 검을 갖고 있습니다. 아래와 같이 i를 외부와 내부의 scope를 만들어 정상적으로 실행할 수 있습니다.
function sumMatrix(matrix: number[][]) {
let sum = 0;
for (let i = 0; i < matrix.length; i++) {
var currentRow = matrix[i];
for (let i = 0; i < currentRow.length; i++) {
sum += currentRow[i];
}
}
return sum;
}
Block-scoped variable capturing
아래의 경우 getCity()가 반환될 때 city를 capturing 해두었기 때문에 city의 block이 벗어났어도 에러없이 사용할 수 있습니다.
function theCityThatAlwaysSleeps() {
let getCity;
if (true) {
let city = "Seattle";
getCity = function() {
return city;
};
}
return getCity();
}
Const
const도 이전과 다르지 않게 선언할 수 있습니다.
const numLivesForCat = 9;
let과 다르게 안의 값을 바꿀 수 없다. 그러나 scope의 기준이나 재할당을 할 수 없는 것은 같습니다.
그렇지만 const 변수의 내부 상태는 변경가능합니다.
const numLivesForCat = 9;
const kitty = {
name: "Aurora",
numLives: numLivesForCat,
}
// Error
kitty = {
name: "Danielle",
numLives: numLivesForCat
};
// all "okay"
kitty.name = "Rory";
kitty.name = "Kitty";
kitty.name = "Cat";
kitty.numLives--;
Destructuring(비구조화)
비구조화는 구조화된 배열을 분리하여 개별적인 변수에 할당할 수 있게 해주는 방법입니다.
Array Destructuring
비구조화 할당을 통해 배열 값을 더 쉽게 나누어 줄 수 있다.
// Destructuring
let input = [1, 2];
let [first, second] = input;
console.log(first); // 1;
console.log(second); // 2;
// bad method
first = input[0];
second = input[1];
또한 아래와 같이 값도 쉽게 바꿀 수 있다.
[first, second] = [second, first];
그리고 함수에서 파라미터로 사용할 수 있습니다.
function f([first, second]: [number, number]) {
console.log(first);
console.log(second);
}
f([1, 2]);
...구문을 사용하여 하나의 변수에 나머지의 값을 할당할 수 있습니다.
const [third, ...forth] = [1, 2, 3, 4];
console.log(third); // 1
console.log(forth); // [2, 3, 4]
또는 특정 값을 선택하여 받거나 한 변수에 하나의 값만을 넣을 수 있습니다.
let [first] = [1, 2, 3, 4];
console.log(first);
let [, second, , forth] = [ 1, 2, 3, 4];
console.log(second); // 2
console.log(forth); // 4
tuple destructuring
tuple도 위와 같이 비구조화할당을 할 수 있습니다.
let tuple: [number, string, boolean] = [7, "Hello", false];
let [a, b, c] = tuple; //a number, b string, c boolean
하지만 개수를 맞춰주지 않으면 에러가 발생합니다.
let [a, b, c, d] = tuple; // Error no element at index 3
배열과 같이 ...을 사용할 수 있다.
let [a, ...b] = tuple; //b는 false와 Hello가 들어간다.
Object destructuring
객체또한 비구조화할당을 할 수 있다.
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, b } = o; // 필요 없는 값인 c등을 무시할 수 있다.
json형태에서 사용하기 위해서는 o의 key 값과 동일하게 맞추어 주어야합니다.
let { a, ...fire } = o;
console.log(fire.b, fire.c);
a를 제외한 나머지는 ...을 사용하여 받을 수 있습니다.
property destructuring
json을 비구조화 할당으로 받을 때 key의 이름이 아닌 다른 이름으로 받을 수 있다. 기존방법으로는 두줄을 사용해야하지만 이 방법을 사용하면 한줄로 마무리할 수 있다.
// 요소 이름 변환
let { a: newName1, b: newName2 } = o;
// 기존 방법
let newName1 = o.a;
let newName2 = o.b;
비구조화 할당을 할 때 특정한 타입을 지정하고 있지 않은데 타입을 지정해주는 것이 다른 사람이 보기에 안헷갈리고 좋다.
let { a, b } : {a:string, b:number} = o;
default values
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject;
}
?여기서 물음표는 b의 값을 선택적으로 넣었다 뺐다 해도 된다는 의미입니다. 그리고 아래의 비구조화할당에서 b에 아무값도 대입이 안되면 default로 1001을 대입한다는 의미입니다.
Function declarations
함수의 파라미터를 설정하는데도 비구조화를 사용할 수 있습니다.
type C = { a: string; b?: number };
function f6({ a, b }: C): void {}
그리고 trick과 같이 오른쪽의 {}를 사용하는 패턴을 기억해야 합니다.
function f({ a="", b=0 } = {}): void {}
f();
그런 다음 기본 초기화 대신에 비구조화 프로퍼티를 추가적인 옵션으로 선택할 수 있게 만들어야합니다.
function f8({ a, b = 0 } = { a: "" }): void {}
f8({ a: "yes" }); //ok default b = 0
f8(); // a= "",
f8({}); // error 인수를 제공하려면 a가 필수입니다.
사실 글을 작성하면서도 많이 혼란스러운 문법이다. 그래서 최대한 간단하고 기본적이게 유지하는 것이 좋을 것 같습니다.
Spread
spread는 비구조화의 정반대의 개념이다. 배열에 있는 값을 다른 배열에 퍼트리는 것이 가능하다. 모든 값은 왼쪽부터 오른쪽까지 차례대로 spread 된다.
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second];
object또한 spread가 가능하다.
let defaults = { foot: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, foot: "rich" };
하지만 아래와 같이 key값이 동일한 경우 덮어 씌워집니다.
let test = { sex: "man" };
let test2 = { sex: "woman", ...test };
console.log(test2); // man
그리고 객체를 spread하는데 큰 제한이 있는데 spread할 때 객체의 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties 여기 있는 것만이 spread됩니다. 즉 method는 잃게 됩니다.
class C {
p = 12;
m() {
}
}
let c = new C();
let clone = { ...c };
clone.p; // ok
clone.m(); // error!
또 generic function을 spread하는 것을 인정하지 않습니다.
'typescript > typescript-grammar' 카테고리의 다른 글
6. typescript - class (0) | 2020.03.06 |
---|---|
5. typescript - interfaces (0) | 2020.03.03 |
3. typescript - 타입 (0) | 2020.02.27 |
2. typescript - 개발환경 설정 (0) | 2020.02.27 |
1. typescript - 특장점 (0) | 2020.02.26 |