AかつBのように定義する
type &
type Engineer = {
name: string,
role: string
}
type Blogger = {
name: string,
follower: number
}
type EngineerBlogger = Engineer & Blogger
const yukilulu: EngineerBlogger = {
name: "yukilulu",
role: "engineer",
follower: 1000
}
console.log(yukilulu)
Engineer & Blogger
&
で繋げる
interface extends
interface Engineer {
name: string,
role: string
}
interface Blogger {
name: string,
follower: number
}
interface EngineerBlogger extends Engineer, Blogger {}
const yukilulu: EngineerBlogger = {
name: "yukilulu",
role: "engineer",
follower: 1000
}
console.log(yukilulu)
nterface EngineerBlogger extends Engineer, Blogger {}
extends
で繋げる
条件文で型を絞る
typeof
型で指定する
function toUpperCaseFunc(x: string | number) {
if (typeof x === "string") {
return x.toUpperCase();
}
return "";
}
string | number
number型はtoUpperCase()
のメソッドを使えないのでエラーになる
if (typeof x === "string") {
return x.toUpperCase();
}
なので typeof
でstring型のみにif文で分岐して利用できるようにする
in
プロパティで指定する
interface Engineer {
name: string,
role: string
}
interface Blogger {
name: string,
follower: number
}
type NomadWorker = Engineer | Blogger
function describeProfile(nomadWorker: NomadWorker) {
console.log(nomadWorker.name); // 共通のnameだけが現在表示できる
if ("role" in nomadWorker) {
console.log(nomadWorker.role) // roleを持っているEngineerの型に絞り込まれた
}
if ("follower" in nomadWorker) {
console.log(nomadWorker.follower) // followerを持っているBloggerの型に絞り込まれた
}
}
console.log(nomadWorker.name); // 共通のnameだけが現在表示できる
この時点ではEngineerかBloggerとどちらなの状態かわからないので共通のnameのみを使える
if ("role" in nomadWorker) {
console.log(nomadWorker.role) // roleを持っているEngineerの型に絞り込まれた
}
"role" in nomadWorker
をつかってroleを持っているEngineerの型に絞り込まれた
if ("follower" in nomadWorker) {
console.log(nomadWorker.follower) // followerを持っているBloggerの型に絞り込まれた
}
"follower" in nomadWorker
を使ってfollowerを持っているBloggerの型に絞り込まれた
instanceof
インスタンスで絞り込む
class Dog {
speak() {
console.log("bow-bow")
}
}
class Bird {
speak() {
console.log("tweet-tweet")
}
fly() {
console.log("flutter")
}
}
type Pet = Dog | Bird
function havePet(pet: Pet) {
pet.speak(); // 共通のspeakはそのまま使える
if (pet instanceof Bird) {
pet.fly(); // petはBirdのインスタンスであるという指定しからBirdの型であると絞り込まれた
}
}
havePet(new Bird());
pet.speak()
// 共通のspeakはそのまま使える
if (pet instanceof Bird) {
pet instanceof Bird
petはBirdのインスタンスであるという指定しからBirdの型であると絞り込まれた
タグ付きユニオンで分岐させる kind
リテラル型をうまく利用する
kind:"dog" = "dog"
class Dog {
kind:"dog" = "dog"
speak() {
console.log("bow-bow");
}
sit() {
console.log("sit")
}
}
class Bird {
kind:"bird" = "bird"
speak() {
console.log("tweet-tweet");
}
fly() {
console.log("flutter");
}
}
type Pet = Dog | Bird;
function havePet(pet: Pet) {
pet.speak(); // 共通のspeakはそのまま使える
switch (pet.kind) { // kindで分岐させる
case "dog":
pet.sit();
break
case "bird":
pet.fly()
break
}
}
havePet(new Bird());
kind:"dog" = "dog"
kind: "文字列a" = "文字列a"
でkindの中に入る文字列を固定する
switch (pet.kind) { // kindで分岐させる
case "dog":
pet.sit();
break
case "bird":
pet.fly()
break
}
それをkind
を使ってswitch文で分岐させる
interfaceでの書き方
kind: "engineer"
型アサーションを使って上書きする
const input = document.getElementById("input");
input.value = "init input name";
そのままだと HTMLElementといういう型になって valueを使うことはできない
後ろに as
をつける
Reactを使う場合を後ろにasをつけるほうがよい
理由はタグが紛らわしくなるから
const input = document.getElementById("input") as HTMLInputElement;
input.value = "init input name";
as HTMLInputElement
を後ろにつけて HTMLInputElement
型だと上書きする
変数を分けないで書く
(document.getElementById("input") as HTMLInputElement).value = "init value"
()
で囲ってその後ろにプロパティをつける
先頭に <>
をつける
const input = <HTMLInputElement>document.getElementById("input");
input.value = "init input name";
<HTMLInputElement>
をつけて HTMLInputElement
型とする
関数のオーバーロード
function toUpperCaseFunc(x: string): string;
function toUpperCaseFunc(x: number): number;
function toUpperCaseFunc(x: string | number) {
if (typeof x === "string") {
return x.toUpperCase();
}
return x;
}
const val = toUpperCaseFunc(3) // number型になっている
console.log(val)
const val2 = toUpperCaseFunc("hello") // string型になっている
console.log(val2)
function toUpperCaseFunc(x: string): string;
function toUpperCaseFunc(x: number): number;
function toUpperCaseFunc(x: string | number) {
if (typeof x === "string") {
return x.toUpperCase();
}
return x;
}
function toUpperCaseFunc(x: string): string;
function toUpperCaseFunc(x: number): number;
それぞれを関数の上に書く
それによってしっかりした型で帰るようになる
オプショナルチェイン ?
interface DownloadData {
id: number,
user?: {
name: string
}
}
const downloadData:DownloadData = {
id: 1
}
console.log(downloadData.user?.name)
user?: {
name: string
}
user
がundefinedであることを許容している場合
console.log(downloadData.user?.name)
downloadData.user?.name
?
をつけることでなかったらundefined
を返す あれば そのまま返すと設定することができる
nullish coalecing ??
const userData = downloadData.user ?? "no-user"
??
をつけることで undefined または null のときに 後ろのものが代入される
注意 OR演算子だと起こり得る事
const userData2 = downloadData || "no-user"
||
これだと 0 や false というデータが入っていても "no-user"
が入ってしまうことに注意
オブジェクトのメンバーの型を取得するlookup型
参考:
type Response = {
users: {
id: number
name: string
email: string
}[]
products: {
id: number
name: string
price: number
}[]
}
type Users = Response['users']
type User = Users[0]
type Products = Response['products']
type Product = Products[0]
const user: User = { id: 1, name: 'Alice', email: 'alice@example.com' }
const product: Product = { id: 1, name: 'Apple', price: 100 }
type Users = Response['users']
type User = Users[0]
type Products = Response['products']
type Product = Products[0]
これで抽出して定義することができるようになる
書き方は []
配列で書く
interfaceの関数のオーバーロード
interface TmpFunc {
(a: string): number,
(a: number): number
}
const tmpFunc: TmpFunc = function (a: number | string) {
console.log(a);
return 0
}
(a: number | string)
を|
でわける
型の互換性
インターセクションのオーバーロード
interface FuncA {
(a: string, b: number): number,
(a: number, b:string): number
}
interface FuncB {
(a: string): number
}
let intersectionFunc: FuncA & FuncB;
intersectionFunc = function (a: number | string, b?: string | number) {
console.log(`${a}: ${b} `)
return 0
}
let intersectionFunc: FuncA & FuncB;
&
で繋げる
intersectionFunc = function (a: number | string, b?: string | number) {
console.log(`${a}: ${b} `)
return 0
}
-
|
で繋げる -
b?: string | number
はFuncBで使われていない可能性があるので?
を使う必要がある
レストパラメーターに型を指定する
レストパラメーターとは引数などに何個で入れられるようにする書き方
...arg
のように書く
配列の中身がすべて同じ型
function addvancedFn(...arg: number[]):void {
console.log(arg)
}
addvancedFn(1, 2, 3)
...arg: number[]
ですべて同じ方になる
配列の中身が必ず個数が一致しなくてもよい書き方
function addvancedFn(...arg: [string, number, boolean?]):void {
console.log(arg)
}
addvancedFn("1", 2)
...arg: [string, number, boolean?]
?
をつけてなくてもいい状態にする
必ず後ろから?
をつける
前からは付けれない
配列の途中まで型をしてあとはレストパラメーターのように使う
function addvancedFn(...arg: [string, number, boolean, ...number[]]):void {
console.log(arg)
}
addvancedFn("1", 2, false, 2 ,3 ,4, 5)
...number[]
一番うしろに配列をつける
配列やタプルをreadonly
にする
配列
readonlyなのでpushなどの変更もできなくなる
function addvancedFn(...arg: readonly number[]):void {
console.log(arg)
// arg.push("A");
}
addvancedFn(1, 2, 3, 4)
...arg: readonly number[]
argの後ろに配列の前につける
タプル
function addvancedFn(...arg: readonly [string, number, boolean, ...number[]]):void {
console.log(arg)
// arg.push("A");
}
addvancedFn("1", 2, false, 2 ,3 ,4, 5)
...arg: readonly
argの後ろ 配列の前につける
使わないほうがいい
インデックスシグネチャ オブジェクトに追加できるようにする機能
type MovietheatreSeatingAssigment = {
[seatNUmber: string]: string;
};
非nullアサーション nullを許容しないを簡潔に書く !
参考(@k_kind ):
const inputElement = document.getElementById('input')!