Mac osだと、
Shift + Option + Fキー
で整形してくれました。
デフォルトでformatterがインストールされているようです。Golangだと、
% go fmt hoge.go
のようにコマンドを入れても良いですが、実は”Shift + Option + F”で同じように整形されました。ショートカットキーで扱える方が便利ですね。
admin
la vie libre
Mac osだと、
Shift + Option + Fキー
で整形してくれました。
デフォルトでformatterがインストールされているようです。Golangだと、
% go fmt hoge.go
のようにコマンドを入れても良いですが、実は”Shift + Option + F”で同じように整形されました。ショートカットキーで扱える方が便利ですね。
admin
なんのことかは、以下のコードがわかりやすいだろう、o’reillyからほぼそのままですが、
// restricted polymorphism
type TreeNode = {
value: string
}
type LeafNode = TreeNode & {
isLeaf: true
}
type InnerNode = TreeNode & {
children: [TreeNode] | [TreeNode, TreeNode]
}
let a: TreeNode = {value: 'a'}
let b: LeafNode = {value: 'b', isLeaf: true}
let c: InnerNode = {value: 'c', children: [b]}
let a1 = mapNode(a, _ => _.toUpperCase())
let b1 = mapNode(b, _ => _.toUpperCase())
let c1 = mapNode(c, _ => _.toUpperCase())
function mapNode<T extends TreeNode>( // if omit extends, node.value makes error since TypeScript
node: T, // cann't define type of the value
f: (value: string) => String
): T{
return {
...node,
value: f(node.value)
}
}
console.log(a, a1) // { value: 'a' } { value: 'A' }
console.log(b, b1) // { value: 'b', isLeaf: true } { value: 'B', isLeaf: true }
console.log(c, c1) // { value: 'c', children: [ { value: 'b', isLeaf: true } ] } { value: 'C', children: [ { value: 'b', isLeaf: true } ] }
TreeNode以下をtype定義しているので、それを継承したTはnode.valueにアクセス可能、TreeNodeを継承しないでTだけならばnode.valueはTypeScriptが型を決められないのでエラーになります。
制約(この場合にはTreeNode)が複数必要な場合にはそれらを&で連結すれば良い。
admin
どちらもおんなじ機能じゃない?と思いましたが当然別物です。constは変数の変更禁止(プロパティは変更できる)、readonlyはプロパティの変更禁止(変数は変更できる)の違いです。
// const vs readonly
const cons_a = {b: 2} // variable can not be changed but property can be changed
cons_a.b = 1 // property is changeable
let const_b: {readonly b: number} = {b: 2} // property can not be changed but variable can be changed
const_b = {b: 1} // variable is changeable
したがってどちらも変更できないようにするには、constとreadonlyの組み合わせ使用になります。せっかくTypeScriptが型を厳密の管理、変更不可もその一部ですから、利用しない手はないでしょうから変更できない変数やプロパティは明確にしてしてコンパイラのチェック機能を使うべきです。
admin
TypeScriptも静的型付け言語なのでgenericsが使えます。
以下はかんたんなサンプルコードですが、配列呼び出しにnumber[]とstring[]のケースです。
// generics
function comp<T>(arg: T[], comp: T): T[]{
let ret: T[] = []
for (let i = 0; i < arg.length; i++){
if (arg[i] === comp){
ret.push(arg[i])
}
}
return ret
}
console.log(comp([3, 2, 8, 10], 3))
console.log(comp(['3', '2', '8', '10'], '3'))
結果は想定通りに、
[ 3 ]
[ '3' ]
genericsはpolymorphism実現のための一つの手法なので、他にも実現手段はあります。
admin
関数の型定義と呼び出しシグネチャーの例として、以下のrest parameterのコードを例にしてみます。
https://isehara-3lv.sakura.ne.jp/blog/2023/06/15/rest-parametertypescript/
// using call signature以下が呼び出しシグネチャーで書き換えてみたものですが、re_tに型情報をsrで与えているので、型のアノテーションが不要になりますから、型定義と関数の実態の分離といっても良さそうです。
// rest parameter (type safe compared to arguments method)
function sumRest(message: string, ...numbers: number[]):[string, number]{
return [message, numbers.reduce((total, n) => total + n, 1)]
}
let res: [string, number] = sumRest('sum :', 1, 2, 3, 4, 5)
console.log(res[0], res[1] )
// using call signature
type sr = (message: string, ...numbers: number[]) => [string, number]
let re_t:sr = (message, ...numbers) => [message, numbers.reduce((total, n) => total + n, 1)]
console.log(re_t('call signature', 1, 2, 3, 4, 5))
実行結果:戻りは配列表記のままになってますが、
[ 'call signature', 16 ]
admin
関数に引数を渡す時に、不定長の場合の渡し方で配列を使った場合とrest parameterを使った場合です。
配列の場合はあくまで引数は配列が一個渡されるだけで、呼び出し側も配列で呼び出し。
rest parameterの場合には、呼び出し側は可変長引数を羅列ですから明らかに別物です。
// argument as an array
function sum(numbers: number[]): number{
return numbers.reduce((total, n) => total + n, 1) // the return value starts with 1
}
console.log(sum([1, 2, 3, 4, 5])) // 16
// rest parameter (type safe compared to arguments method)
function sumRest(message: string, ...numbers: number[]):[string, number]{
return [message, numbers.reduce((total, n) => total + n, 1)]
}
let res: [string, number] = sumRest('sum :', 1, 2, 3, 4, 5)
console.log(res[0], res[1] ) // sum : 16
sumRest()の呼び出し時のresの戻り値型指定は不要ですがコメントのようなもの。sumRest()の定義側では戻り値の型指定は必須です。
admin
関数のデフォルトパラメータを、以下でContextという形で定義した時に、関数で設定するときは以下のようなやり方。type指定で要素をオプション指定しているので、log関数では指定したい方だけ指定すれば良い。
// default parameter
type Context = {
appID?: string,
userID?: string
}
function log(message: string, context: Context = {userID:'aaabID'}){
let time = new Date().toString()
console.log(time, message, context.userID)
}
let id: Context = {userID: 'xxxyID'}
log('parameter', id) // Wed Jun 14 2023 14:43:05 GMT+0900 (日本標準時) parameter xxxyID
log('parameter') // Wed Jun 14 2023 14:43:05 GMT+0900 (日本標準時) parameter aaabID
TypeScriptというだけあって、型が中心にあるように感じる言語です。
admin
VScodeでTypeScriptのコンパイルを行なって、ソースエディター上に.tsと.jsファイルを並べて表示させると、
こんなエラーが表示されます。コンパイルも実行も問題なくできるのですが、
対策はエディタ画面に同時表示させないこと、というだけですけれども。
ディレクトリの構成は、こんな感じです。
tsconfig.jsonは、
npx tsc --init
で作成。
% npx tsc --init
Created a new tsconfig.json with:
TS
target: es2016
module: commonjs
strict: true
esModuleInterop: true
skipLibCheck: true
forceConsistentCasingInFileNames: true
You can learn more at https://aka.ms/tsconfig
admin
ちょっと見紛らわしい、union(論理和)とintersection(論理積)です。
// union & intersection of types
type Cat = {name: string, purrs: boolean}
type Dog = {name:string, barks: boolean}
type CatOrDog = Cat | Dog
type CatAndDog = Cat & Dog
let a_o: CatOrDog = {
name: 'ball', // need not to specify all properties
barks: false
}
let a_a: CatAndDog = {
name: "Dounald",
barks: false, // need to specify all properties of the Dog and Cat
purrs: false
}
論理和(|)であるa_oはプロパティのいずれかが記述されてればいいけれども、論理積(&)であるa_aはプロパティを全て記述しないとエラーになります。
実際のコードではunionの方が遥かに登場機会が多いようですが、いずれかのプロパティを持てば良いという定義からしてそうなりそうです。
admin
TypeScriptはその名の通り、基本的に型を厳密に定義しないといけませんが、タイトルの通り似たような三つのオブジェクト定義が存在します。その性質の違いを見るのが以下のコードです。
// object, Object and {}
let o1: {}
let o2: object
let o3: Object // Object is an interface
o1 = {a: 2} // object
o1 = 123 // primitive
o2 = {a: 2}
//o2 = 123 // primitive is not usable
o3 = {a: 2}
o3 = 123
o1 = {toString() {return 1}} // accept any type of object
//o3 = {toString() {return 1}} // treat o3 as a string type which is a predefined type
・{}, Object : オブジェクトもプリミティブも代入可能
・object : オブジェクトのみ代入可能
実はObjectはインターフェースであると、またTypeScriptではプリミティブ以外は全てオブジェクトです。
オブジェクトの定義方法としては、
オブジェクトとプリミティブの分離のためと思いますが、
admin