[๐ค] TypeScript satisfies ์ฐ์ฐ์: ํ์ ์ถ๋ก ๊ณผ ์์ ์ฑ์ ๋์์ ์ก๋ ๋น๋ฒ
TypeScript์ `satisfies` ์ฐ์ฐ์๋ฅผ ํ์ฉํ์ฌ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ์ ์ ์งํ๋ฉด์๋ ์๊ฒฉํ ํ์ ์์ ์ฑ์ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์ค์ฉ์ ์ธ ์์๋ฅผ ํตํด ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํฉ๋๋ค.
์ ๋ณด๐ค ์ด ํฌ์คํ ์ Gemini 2.5 Flash AI๊ฐ ์์ฑํ์ด์.
๋ด์ฉ์ ์ ํ์ฑ์ ์ํด ๊ฒํ ๋ฅผ ๊ฑฐ์ณค์ง๋ง, ์ค๋ฌด ์ ์ฉ ์ ๊ณต์ ๋ฌธ์๋ฅผ ํจ๊ป ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ์ฉํ ํTypeScript์
satisfies์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ์ ์ ์งํ๋ฉด์๋ ์๊ฒฉํ ํ์ ์์ ์ฑ์ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ๋ฐฐ์๋ด ๋๋ค.
์๋
ํ์ธ์! 10๋
์ด์ ํ๋ก ํธ์๋์ ๋ฐฑ์๋๋ฅผ ๋๋๋ค๋ฉฐ ๊ฐ๋ฐํด ์จ ์๋์ด ๊ฐ๋ฐ์์
๋๋ค.
์ค๋์ ๋ง์ ๊ฐ๋ฐ์๋ถ๋ค์ด TypeScript๋ฅผ ์ฌ์ฉํ๋ฉด์ ํ ๋ฒ์ฏค์ ๊ณ ๋ฏผํด ๋ดค์ ๋ฒํ ๋ฌธ์ , ๋ฐ๋ก "ํ์
์ถ๋ก ์ ์ ์ฐ์ฑ๊ณผ ํ์
์์ ์ฑ์ ๋์์ ์ก๋ ๋ฐฉ๋ฒ"์ ๋ํด ์ด์ผ๊ธฐํด ๋ณด๋ ค๊ณ ํด์.
ํนํ TypeScript 4.9๋ถํฐ ๋์
๋ satisfies ์ฐ์ฐ์๊ฐ ์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ์ฐ์ํ๊ฒ ํด๊ฒฐํด ์ฃผ๋์ง ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
0๏ธโฃ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ๊ณผ ํ์ ์์ ์ฑ ์ฌ์ด์ ๋๋ ๋ง
TypeScript๋ ๊ฐ๋ ฅํ ํ์
์์คํ
์ ํตํด ๊ฐ๋ฐ ์์ฐ์ฑ๊ณผ ์ฝ๋ ์์ ์ฑ์ ๋์ฌ์ฃผ์ง๋ง, ๋๋ก๋ ํ์
์ ์ ๋ฐฉ์์ ๋ฐ๋ผ ๊ฐ๋ฐ ๊ฒฝํ์ด ๋ถํธํด์ง ๋๊ฐ ์์ด์.
์๋ฅผ ๋ค์ด, ์ด๋ค ๊ฐ์ฒด๊ฐ ํน์ ์ธํฐํ์ด์ค๋ฅผ ๋ง์กฑํด์ผ ํ์ง๋ง, ๋์์ ๊ทธ ๊ฐ์ฒด์ ๊ฐ๋ณ ํ๋กํผํฐ๋ ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ ์ ์งํ๊ณ ์ถ์ ๋๊ฐ ์์ต๋๋ค.
์๋ ์ฝ๋๋ฅผ ๋ณด์๊ฒ ์ด์?
type Colors = "red" | "green" | "blue"; interface Palette { primary: Colors; secondary: Colors; } // ๋ฌธ์ ์ํฉ: Palette ํ์ ์ ๋ช ์ํ๋ฉด, 'red'๋ string์ด ์๋๋ผ 'red' ๋ฆฌํฐ๋ด ํ์ ์ด์ด์ผ ํ๋๋ฐ... const myPalette: Palette = { primary: "red", secondary: "green", tertiary: "yellow" // Error: Object literal may only specify known properties }; // myPalette.primary๋ 'red' ๋ฆฌํฐ๋ด ํ์ ์ด ์๋๋ผ Colors ํ์ ์ด ๋์ด๋ฒ๋ ค์. const primaryColor = myPalette.primary; // type: Colors ('red' | 'green' | 'blue') // ๋ง์ฝ 'red' ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด? // const specificColor: "red" = primaryColor; // Error: Type 'Colors' is not assignable to type '"red"'.
์ ์์์์ myPalette์ Palette ํ์
์ ๋ช
์ํ๋ฉด, tertiary ๊ฐ์ ์ถ๊ฐ ํ๋กํผํฐ๋ฅผ ๊ฐ์ง ์ ์๊ฒ ๋ฉ๋๋ค.
๋ํ, myPalette.primary๋ "red"๋ผ๋ ๊ตฌ์ฒด์ ์ธ ๋ฆฌํฐ๋ด ํ์
์ด ์๋ Colors ์ ๋์จ ํ์
์ผ๋ก ์ถ๋ก ๋์ด, ๋์ค์ "red" ๋ฆฌํฐ๋ด ํ์
์ด ํ์ํ ๊ณณ์ ์ง์ ํ ๋นํ๊ธฐ ์ด๋ ค์์ ธ์.
์ด๋ ํ์
์ถ๋ก ์ ์ ์ฐ์ฑ์ ์๊ฒ ๋ง๋๋ ๋ํ์ ์ธ ๊ฒฝ์ฐ์
๋๋ค.
1๏ธโฃ as ํค์๋์ ํ๊ณ์ ๋ฌธ์ ์
์ด๋ฐ ์ํฉ์์ ๋ง์ ๊ฐ๋ฐ์๋ถ๋ค์ด as ํค์๋๋ฅผ ์ฌ์ฉํด ๋ณด์
จ์ ๊ฑฐ์์.
as ํค์๋๋ ์ปดํ์ผ๋ฌ์๊ฒ "๋ด๊ฐ ๋ ์ ์๋, ์ด ํ์
์ ๋ฏฟ์ด์ค"๋ผ๊ณ ์ง์ํ๋ ์ญํ ์ ํฉ๋๋ค.
type Colors = "red" | "green" | "blue"; interface Palette { primary: Colors; secondary: Colors; } // 'as' ํค์๋ ์ฌ์ฉ ์์ const myPaletteWithAs = { primary: "red", secondary: "green", tertiary: "yellow" // ์ด ๋ถ๋ถ์ ์๋ฌ๊ฐ ๋์ง ์์์ (as Palette๊ฐ ์ ์ฒด๋ฅผ ๋ฎ์ด์์) } as Palette; // ํ์ง๋ง 'tertiary'๋ Palette ํ์ ์ ์์ผ๋ฏ๋ก ์ ๊ทผ ์ ์๋ฌ๊ฐ ๋ฐ์ํด์. // console.log(myPaletteWithAs.tertiary); // Error: Property 'tertiary' does not exist on type 'Palette'. // ๋ํ, myPaletteWithAs.primary๋ ์ฌ์ ํ Colors ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค. const primaryColorFromAs = myPaletteWithAs.primary; // type: Colors
as ํค์๋๋ ๋ ๊ฐ์ง ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
์ฒซ์งธ, ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์๋ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํด๋ ์ปดํ์ผ ์์ ์ ์ค๋ฅ๋ฅผ ์ก์์ฃผ์ง ๋ชปํฉ๋๋ค.
as Palette๊ฐ ๊ฐ์ฒด ์ ์ฒด์ ์ ์ฉ๋๋ฉด์ tertiary ํ๋กํผํฐ์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ฑด๋๋ฐ๊ฒ ๋๋ ๊ฒ์ด์ฃ .
๋์งธ, ์ฌ์ ํ ๊ฐ๋ณ ํ๋กํผํฐ์ ๊ตฌ์ฒด์ ์ธ ๋ฆฌํฐ๋ด ํ์
์ ๋ณด๋ฅผ ์์ด๋ฒ๋ฆฌ๊ณ , ๋ช
์๋ ์ธํฐํ์ด์ค์ ์ ๋์จ ํ์
์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก as๋ ํ์
์์ ์ฑ์ ์ฝํ์ํค๊ฑฐ๋, ์ํ๋ ํ์
์ถ๋ก ์ ๋ฐฉํดํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์.
0๏ธโฃ satisfies ์ฐ์ฐ์๋ ๋ฌด์์ธ๊ฐ์?
TypeScript 4.9๋ถํฐ ๋์
๋ satisfies ์ฐ์ฐ์๋ ์ด๋ฌํ ๋๋ ๋ง๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํ์ํ์ด์.
satisfies๋ "์ด ํํ์์ด ํน์ ํ์
์ ์๊ตฌ์ฌํญ์ ๋ง์กฑํ๋์ง ํ์ธํ๋, ๊ทธ ํํ์์ ์๋ ์ถ๋ก ๋ ํ์
์ ๊ทธ๋๋ก ์ ์งํด ์ค"๋ผ๊ณ TypeScript ์ปดํ์ผ๋ฌ์๊ฒ ์ง์ํฉ๋๋ค.
์ฆ, ํ์
๊ฒ์ฌ๋ ์ํํ์ง๋ง, ํ์
์ถ๋ก ์ ๋ณ๊ฒฝํ์ง ์๋ ๊ฒ์ด์ฃ .
์ด๊ฒ์ as ํค์๋์๋ ๋งค์ฐ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ด์์.
as๋ ๊ฐ์ ๋ก ํ์
์ ๋ณ๊ฒฝํ๋ ๋ฐ๋ฉด, satisfies๋ ํ์
์ ๋ณ๊ฒฝํ์ง ์๊ณ ๋จ์ง "ํ์ธ"๋ง ํ๋ ์ญํ ์ ํฉ๋๋ค.
1๏ธโฃ as์ satisfies์ ๊ฒฐ์ ์ ์ธ ์ฐจ์ด
as์ satisfies์ ์ฐจ์ด๋ฅผ ๋ช
ํํ๊ฒ ์ดํดํ๋ ๊ฒ์ด ์ค์ํด์.
์ ๋ณด
as Type: "์ด ๊ฐ์Type์ผ๋ก ๊ฐ์ฃผํด ์ค. ๋ด๊ฐType์ด๋ผ๋ ๊ฒ์ ๋ณด์ฅํ ๊ฒ."-> ํ์ ์ ๊ฐ์ ๋ก ๋ณ๊ฒฝํ๊ณ , ์๋์ ์ธ๋ถ ํ์ ์ ๋ณด๋ฅผ ์์ ์ ์์ต๋๋ค. ์๋ชป ์ฌ์ฉํ๋ฉด ๋ฐํ์ ์ค๋ฅ๋ก ์ด์ด์ง ์ ์์ด์.
์ ์ฉํ ํ
satisfies Type: "์ด ๊ฐ์ดType์ ์๊ตฌ์ฌํญ์ ๋ง์กฑํ๋์ง ํ์ธํด ์ค. ํ์ง๋ง ์ด ๊ฐ์ ํ์ ์ ์๋ ์ถ๋ก ๋ ํ์ ๊ทธ๋๋ก ์ ์งํด ์ค."-> ํ์ ๊ฒ์ฌ๋ง ์ํํ๊ณ , ์๋์ ์ธ๋ถ ํ์ ์ ๋ณด๋ฅผ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค. ํ์ ์์ ์ฑ์ ๋์ด๋ฉด์๋ ์ ์ฐํ ํ์ ์ถ๋ก ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
์ด์ satisfies๋ฅผ ์ฌ์ฉํ๋ฉด ์์์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค์ด ์ด๋ป๊ฒ ํด๊ฒฐ๋๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
type Colors = "red" | "green" | "blue"; interface Palette { primary: Colors; secondary: Colors; } // satisfies ์ฐ์ฐ์ ์ฌ์ฉ ์์ const myPaletteSatisfies = { primary: "red", secondary: "green", // tertiary: "yellow" // Error: Object literal may only specify known properties. // -> satisfies๋ Palette ์ธํฐํ์ด์ค์ ์๋ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋ฉด ์๋ฌ๋ฅผ ๋ฐ์์์ผ์! } satisfies Palette; // myPaletteSatisfies.primary๋ 'red' ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค! const primaryColorFromSatisfies = myPaletteSatisfies.primary; // type: "red" // ์ด์ 'red' ๋ฆฌํฐ๋ด ํ์ ์ด ํ์ํ ๊ณณ์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ด์. const specificColor: "red" = primaryColorFromSatisfies; // No Error! // ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ๋ค๋ฅธ ํ๋กํผํฐ๋ ์๋์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค. const secondaryColorFromSatisfies = myPaletteSatisfies.secondary; // type: "green"
๋ณด์๋ ๊ฒ์ฒ๋ผ satisfies๋ฅผ ์ฌ์ฉํ๋ฉด Palette ์ธํฐํ์ด์ค์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ๊ฒ์ฌํ๋ฉด์๋, primary๊ฐ "red" ๋ฆฌํฐ๋ด ํ์
์ผ๋ก, secondary๊ฐ "green" ๋ฆฌํฐ๋ด ํ์
์ผ๋ก ์ ํํ๊ฒ ์ถ๋ก ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๊ฒ์ด ๋ฐ๋ก satisfies ์ฐ์ฐ์์ ํต์ฌ์ ์ธ ๊ฐ์ ์ด์์!
satisfies ์ฐ์ฐ์๋ ๋ค์ํ ์ค์ ์๋๋ฆฌ์ค์์ ๋งค์ฐ ์ ์ฉํ๊ฒ ํ์ฉ๋ ์ ์์ด์.
๋ช ๊ฐ์ง ์ค์ ๊ฐ๋ฐ์์ ๋ง์ฃผํ ์ ์๋ ์์๋ฅผ ํตํด ๊ทธ ๊ฐ๋ ฅํจ์ ๋ ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค.
0๏ธโฃ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์์ ์ธ๋ถ ํ๋กํผํฐ ํ์ ์ ์งํ๊ธฐ
์ด์ ์ ์ดํด๋ณธ Palette ์์์ ์ ์ฌํ๊ฒ, ์ค์ ๊ฐ์ฒด๋ ๋งคํ ๊ฐ์ฒด๋ฅผ ์ ์ํ ๋ ์ ์ฉํด์.
๊ฐ ํค์ ๊ฐ์ด ํน์ ์กฐ๊ฑด์ ๋ง์กฑํด์ผ ํ์ง๋ง, ๊ฐ ์์ฒด๋ ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ ์ ์งํ๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค.
type LogLevel = "info" | "warn" | "error" | "debug"; interface LoggerConfig { level: LogLevel; format: string; } // ๊ฐ ํ๊ฒฝ๋ณ ์ค์ ์ ์ ์ํ๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค. const appConfigs = { development: { level: "debug", format: "[%level%] %message%", }, production: { level: "info", format: "[%level%] %timestamp% %message%", // maxFileSize: 1024 // Error: Object literal may only specify known properties. // -> LoggerConfig์ ์๋ ์์ฑ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. }, test: { level: "error", format: "[%level%] %message%", }, } satisfies Record<string, LoggerConfig>; // Record<string, LoggerConfig>๋ฅผ ๋ง์กฑํ๋์ง ํ์ธ! // ์ด์ appConfigs.development.level์ "debug" ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค. const devLogLevel = appConfigs.development.level; // type: "debug" // ํ๋ก๋์ ํ๊ฒฝ์ ํฌ๋งท์ ๊ฐ์ ธ์๋ string ๋ฆฌํฐ๋ด ํ์ ์ด ์ ์ง๋ฉ๋๋ค. const prodFormat = appConfigs.production.format; // type: "[%level%] %timestamp% %message%" // ๋ฐ๋ผ์ ์คํ ๋ฐฉ์ง ๋ฐ ์๋ ์์ฑ์๋ ํฐ ๋์์ด ๋ฉ๋๋ค. if (devLogLevel === "debug") { console.log("๋๋ฒ๊ทธ ๋ชจ๋์ ๋๋ค."); } // ๋ง์ฝ satisfies๋ฅผ ์ฌ์ฉํ์ง ์์๋ค๋ฉด devLogLevel์ LogLevel ํ์ ์ด ๋์์ ๊ฑฐ์์. // const devLogLevelWithoutSatisfies: LogLevel = appConfigs.development.level; // type: LogLevel
Record<string, LoggerConfig>๋ฅผ satisfies ํ๋ฉด, appConfigs ๊ฐ์ฒด ์ ์ฒด๊ฐ LoggerConfig์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ๊ฒ์ฌํฉ๋๋ค.
๋์์ appConfigs.development.level๊ณผ ๊ฐ์ ๊ฐ๋ณ ํ๋กํผํฐ๋ 'debug'์ ๊ฐ์ ๊ตฌ์ฒด์ ์ธ ๋ฆฌํฐ๋ด ํ์
์ผ๋ก ์ถ๋ก ๋์ด IntelliSense์ ํ์
์์ ์ฑ ๋ชจ๋๋ฅผ ํ๋ณดํ ์ ์์ด์.
1๏ธโฃ CSS ์์ฑ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์๋ ์์ฑ ํ์ฉ
CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์คํ์ผ ๊ฐ์ฒด๋ฅผ ๋ค๋ฃฐ ๋ satisfies ์ฐ์ฐ์๋ ๋น์ ๋ฐํฉ๋๋ค.
ํน์ CSS ์์ฑ ์งํฉ์ ๋ง์กฑํ๋์ง ํ์ธํ๋ฉด์๋, ๊ฐ๋ฐ์๊ฐ ์ ์ํ ๊ฐ์ ๊ทธ๋๋ก ์ ์งํ๊ณ ์ถ์ ๋ ์ฌ์ฉํด์.
import React from 'react'; type CSSProperties = React.CSSProperties; // ์ ํจํ ์์ ์ฝ๋๋ง ํ์ฉํ๋ ์ ํธ๋ฆฌํฐ ํ์ (์์) type HexColor = `#${string}`; type ValidColor = HexColor | "currentColor" | "transparent" | "inherit"; interface MyComponentStyle { container: CSSProperties & { backgroundColor?: ValidColor }; button: CSSProperties & { color?: ValidColor }; } const styles = { container: { display: "flex", padding: "16px", backgroundColor: "#f0f0f0", // HexColor๋ฅผ ๋ง์กฑํ๋์ง ๊ฒ์ฌ // invalidColor: "not-a-color" // Error: Object literal may only specify known properties }, button: { color: "currentColor", fontSize: "16px", fontWeight: "bold", // hoverColor: "#123" // Error: Object literal may only specify known properties }, } satisfies MyComponentStyle; // styles.container.backgroundColor๋ "#f0f0f0" ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค. const containerBg = styles.container.backgroundColor; // type: "#f0f0f0" // ์ด๋ฅผ ํตํด ์ ํํ ํ์ ์ ๋ณด๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค. const specificBg: "#f0f0f0" = containerBg; // No Error! // ๋ง์ฝ ์คํ๊ฐ ์๋ค๋ฉด ์ฆ์ ์๋ฌ๋ฅผ ๋ฐ์์์ผ์. // styles.container.backgroundColour; // Error: Property 'backgroundColour' does not exist on type '{ display: string; padding: string; backgroundColor: "#f0f0f0"; }'.
styles ๊ฐ์ฒด๊ฐ MyComponentStyle์ satisfies ํ๋์ง ๊ฒ์ฌํจ์ผ๋ก์จ, ์๋ชป๋ CSS ์์ฑ์ด๋ ์ ํจํ์ง ์์ ์์ ๊ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๋์์ backgroundColor์ ๊ฐ์ ์์ฑ๋ค์ "#f0f0f0"์ ๊ฐ์ ๊ตฌ์ฒด์ ์ธ ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์
์ผ๋ก ์ถ๋ก ๋์ด, ๋์ค์ ์ด ๊ฐ์ ํ์ฉํ ๋ ๋ ์ ํํ ํ์
์ ๋ณด๋ฅผ ์ป์ ์ ์์ด์.
2๏ธโฃ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋๋ ์ฝ๋ฐฑ ํจ์ ํ์ ์์ ํ๊ฒ ์ ์ํ๊ธฐ
ํจ์ ๋งค๊ฐ๋ณ์๋ ๋ฐํ ๊ฐ์ ๋ํ ํ์
์ ์ ์ํ ๋๋ satisfies๋ฅผ ํ์ฉํ ์ ์์ด์.
ํน์ ์ธํฐํ์ด์ค๋ฅผ ๋ง์กฑํ๋ ํจ์๋ฅผ ์ ์ํ๋ฉด์๋, ํจ์์ ๋ด๋ถ ๊ตฌํ์์ ์ฌ์ฉ๋๋ ๋งค๊ฐ๋ณ์๋ ๋ก์ปฌ ๋ณ์์ ํ์
์ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์ ์งํ๊ณ ์ถ์ ๋ ์ ์ฉํฉ๋๋ค.
type EventName = "click" | "hover" | "focus"; interface EventHandler { (event: { type: EventName; target: HTMLElement }): void; } const eventHandlers = { handleClick: (event) => { // event.type์ "click" ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค! if (event.type === "click") { console.log("ํด๋ฆญ ์ด๋ฒคํธ ๋ฐ์:", event.target); } }, handleHover: (event) => { // event.type์ "hover" ๋ฆฌํฐ๋ด ํ์ ์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค! console.log("ํธ๋ฒ ์ด๋ฒคํธ ๋ฐ์:", event.target.tagName); // event.target.focus(); // Error: Property 'focus' does not exist on type 'HTMLElement'. // -> HTMLElement์ focus๊ฐ ์์ผ๋ฉด ์๋ฌ ๋ฐ์ (ํ์ ์์ ์ฑ ๋ณด์ฅ) }, } satisfies Record<string, EventHandler>; // eventHandlers.handleClick์ event ๋งค๊ฐ๋ณ์ ํ์ ์ { type: "click"; target: HTMLElement }๋ก ์ถ๋ก ๋ฉ๋๋ค. // ์ด๋ Record<string, EventHandler>์ ์ ์ฝ์ ๋ง์กฑํ๋ฉด์๋, ๊ฐ ํธ๋ค๋ฌ์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ๋ณด๋ฅผ ์ ์งํ๊ฒ ํด์ค๋๋ค. // ์ด ํธ๋ค๋ฌ๋ฅผ ์ฌ์ฉํ ๋๋ ํ์ ์์ ์ฑ์ ๋๋ฆด ์ ์์ด์. const myButton = document.createElement('button'); myButton.addEventListener('click', (e) => { eventHandlers.handleClick({ type: "click", target: e.currentTarget as HTMLElement }); });
์ฌ๊ธฐ์ eventHandlers ๊ฐ์ฒด๊ฐ Record<string, EventHandler>๋ฅผ satisfies ํ๋์ง ๊ฒ์ฌํจ์ผ๋ก์จ, ๋ชจ๋ ํธ๋ค๋ฌ ํจ์๊ฐ EventHandler ์ธํฐํ์ด์ค์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ํ์ธํฉ๋๋ค.
๋์์ handleClick ํจ์ ๋ด๋ถ์ event.type์ "click" ๋ฆฌํฐ๋ด ํ์
์ผ๋ก, handleHover ํจ์ ๋ด๋ถ์ event.type์ "hover" ๋ฆฌํฐ๋ด ํ์
์ผ๋ก ์ ํํ๊ฒ ์ถ๋ก ๋ฉ๋๋ค.
์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ ๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ๋ก์ง์ ์์ฑํ ๋ ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ ๋ณด๋ฅผ ํ์ฉํ ์ ์๊ฒ ๋์ด ์์ฐ์ฑ๊ณผ ์์ ์ฑ ๋ชจ๋๋ฅผ ๋์ผ ์ ์์ด์.
0๏ธโฃ ์ฃผ์ ์ฅ์
satisfies ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ๋ค์ ์ป์ ์ ์์ต๋๋ค.
- ํ์
์์ ์ฑ ํ๋ณด: ํน์ ํ์
์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ์ปดํ์ผ ์์ ์ ๊ฒ์ฌํ์ฌ ์ ์ฌ์ ์ธ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํด์.
์๋ฅผ ๋ค์ด,Palette์์์์tertiary๊ฐ์ ๋ถํ์ํ ํ๋กํผํฐ ์ถ๊ฐ๋ฅผ ๋ง์์ค๋๋ค. - ํ์
์ถ๋ก ์ ์ฐ์ฑ ์ ์ง: ๊ฐ์ ์๋ ์ถ๋ก ๋ ํ์
์ ๊ทธ๋๋ก ์ ์งํ์ฌ, ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ ๋ณด๋ฅผ ํ์ฉํ ์ ์์ด์.
"red"์ ๊ฐ์ ๋ฆฌํฐ๋ด ํ์ ์ ์์ง ์์ IntelliSense์ ์ฝ๋์ ์ ํ์ฑ์ ๋์ฌ์ค๋๋ค. - ๋ถํ์ํ ํ์
๋จ์ธ(
as) ๊ฐ์:asํค์๋๋ฅผ ๋จ์ฉํ ํ์๊ฐ ์์ด ์ฝ๋์ ๊ฐ๋ ์ฑ์ ๋์ด๊ณ ,as๋ก ์ธํ ์ ์ฌ์ ์ธ ๋ฐํ์ ์ค๋ฅ๋ฅผ ์ค์ฌ์ค๋๋ค. - ์๋ ์์ฑ ๋ฐ ๋ฆฌํฉํ ๋ง ์ฉ์ด: ๊ตฌ์ฒด์ ์ธ ํ์ ์ ๋ณด๊ฐ ์ ์ง๋๋ฏ๋ก ๊ฐ๋ฐ ๋๊ตฌ์ ์๋ ์์ฑ ๊ธฐ๋ฅ์ด ๋์ฑ ๊ฐ๋ ฅํด์ง๊ณ , ์ฝ๋ ๋ฆฌํฉํ ๋ง ์์๋ ํ์ ์ค๋ฅ๋ฅผ ์ฝ๊ฒ ๊ฐ์งํ ์ ์์ด์.
1๏ธโฃ ์ฌ์ฉ ์ ์ฃผ์ํ ์
satisfies ์ฐ์ฐ์๋ ๊ฐ๋ ฅํ์ง๋ง, ๋ช ๊ฐ์ง ์ฃผ์ํ ์ ๋ ์์ต๋๋ค.
- TypeScript 4.9 ์ด์์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ:
satisfies๋ TypeScript 4.9 ๋ฒ์ ๋ถํฐ ๋์ ๋ ๊ธฐ๋ฅ์ด๋ฏ๋ก, ํ๋ก์ ํธ์ TypeScript ๋ฒ์ ์ ํ์ธํด์ผ ํฉ๋๋ค.
๊ตฌํ ๋ฒ์ ์์๋ ์ฌ์ฉํ ์ ์์ด์. - ์ค๋ฒํค๋ ๋ฐ์ ๊ฐ๋ฅ์ฑ: ๋งค์ฐ ๋ณต์กํ ํ์
์ ์์ ๋๊ท๋ชจ ๊ฐ์ฒด์
satisfies๋ฅผ ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ์ปดํ์ผ ์๊ฐ์ด ์ฝ๊ฐ ๋์ด๋ ์ ์์ต๋๋ค.
ํ์ง๋ง ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ฑ๋ฅ ์ ํ๋ ๋ฏธ๋ฏธํ๋ฉฐ, ์ป๋ ์ด์ ์ด ํจ์ฌ ์ปค์. as์ ๋์ฒด์ฌ๋ ์๋:satisfies๊ฐas์ ๋ง์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋์ฒดํ ์ ์์ง๋ง,as๋ ์ฌ์ ํ ํน์ ์ํฉ(์: ํ์ ๊ฐ๋๋ฅผ ์ฐํํด์ผ ํ๋ ๋๋ฌธ ๊ฒฝ์ฐ)์์ ํ์ํ ์ ์์ต๋๋ค.
๊ฐ ํค์๋์ ๋ชฉ์ ์ ์ ํํ ์ดํดํ๊ณ ์ ์ ํ๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํด์.
๐ ์ ๋ฆฌํ๋ฉฐ
0๏ธโฃ ํต์ฌ ์์ฝ
์ค๋์ TypeScript์ satisfies ์ฐ์ฐ์์ ๋ํด ์์ธํ ์์๋ณด์์ต๋๋ค.
satisfies๋ ๊ฐ์ ํ์
์ด ํน์ ์ธํฐํ์ด์ค๋ ํ์
์ ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ๊ฒ์ฌํ๋ฉด์๋, ๊ฐ ์์ฒด์ ๊ตฌ์ฒด์ ์ธ ํ์
์ถ๋ก ์ ๊ทธ๋๋ก ์ ์งํ๋ ํ์ ์ ์ธ ๋ฐฉ๋ฒ์ด์์.
์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ค์ ํ์
์์ ์ฑ์ ํด์น์ง ์์ผ๋ฉด์๋ ์ ์ฐํ๊ณ ์ ํํ ํ์
์ ๋ณด๋ฅผ ํ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
as ํค์๋๊ฐ ๊ฐ์ง ์ ์๋ ์ ์ฌ์ ์ธ ์ํ์ ํํผํ๊ณ , ๋ ์์ ํ๊ณ ๊ฐ๋ ฅํ ํ์
์์คํ
์ ๊ตฌ์ถํ๋ ๋ฐ satisfies ์ฐ์ฐ์๊ฐ ํฐ ๋์์ด ๋ ๊ฑฐ์์.
1๏ธโฃ ๋ค์ ๋จ๊ณ๋ก ๋์๊ฐ๊ธฐ
์ด์ ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์ satisfies ์ฐ์ฐ์๋ฅผ ์ ์ฉํด ๋ณผ ์๊ฐ์
๋๋ค!
์ค์ ๊ฐ์ฒด, ์คํ์ผ ๊ฐ์ฒด, ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ฑ ๋ค์ํ ์ํฉ์์ satisfies๋ฅผ ํ์ฉํ์ฌ ์ฝ๋์ ์์ ์ฑ๊ณผ ๊ฐ๋ฐ ์์ฐ์ฑ์ ํ ๋จ๊ณ ๋ ๋์ฌ๋ณด์ธ์.
๊ถ๊ธํ ์ ์ด๋ ๋ ๋
ผ์ํ๊ณ ์ถ์ ๋ถ๋ถ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ง ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์ธ์.
ํจ๊ป ์ฑ์ฅํ๋ ๊ฐ๋ฐ ๋ฌธํ์ ๊ธฐ์ฌํ ์ ์๋๋ก ๋
ธ๋ ฅํ๊ฒ ์ต๋๋ค!
๐ฎ ์ฐธ๊ณ
- TypeScript 4.9 Release Notes - The
satisfiesoperator - Understanding TypeScript's
satisfiesoperator - React.CSSProperties
์ฐ๊ด๋ ํฌ์คํธ
- ๋จ์ด: 1,960๊ฐ23๋ถ
[๐ค] Next.js Server & Client Components, ์ค์ ์์ ํ๋ช ํ๊ฒ ์ ํํ๋ ๊ฐ์ด๋
Next.js App Router์์ Server Components์ Client Components ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด์ ๊ฐ์? ์ด ๊ธ์์ ๋ ์ปดํฌ๋ํธ์ ํต์ฌ ์ฐจ์ด์ , ์ฌ์ฉ ์์ , ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ค์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ฆด๊ฒ์.
- ๋จ์ด: 1,207๊ฐ15๋ถ
[๐ค] React 19 ์๋ก์ด ๊ธฐ๋ฅ: use ํ , Actions, ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ๋ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
React 19์ ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ์ธ use ํ , ์๋ฒ ์ก์ , ๊ทธ๋ฆฌ๊ณ React ์ปดํ์ผ๋ฌ์ ๋์ ๋ฐฐ๊ฒฝ๊ณผ ์ค์ ํ์ฉ ์์๋ฅผ ์ด์ค๊ธ ๊ฐ๋ฐ์ ๋๋์ด์ ๋ง์ถฐ ์์ธํ ์ค๋ช ํฉ๋๋ค. ์ต์ React ์ ๋ฐ์ดํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
- ๋จ์ด: 1,512๊ฐ16๋ถ
[๐ค] Next.js App Router ์บ์ฑ ์ ๋ต: ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ (revalidatePath, revalidateTag) ์๋ฒฝ ๊ฐ์ด๋
Next.js 14 App Router์์ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์บ์ฑ ์ ๋ต๊ณผ revalidatePath, revalidateTag๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์์๋ณด๊ณ ์น ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.