Skip to content

[ja translation] playground-example/4-1 #1419

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//// { compiler: { ts: "4.1.0-dev.20201028", jsx: 4 } }

// Reactのバージョン17には、JSXを変換する際に
// 出力されるJavaScriptに新しい形式が導入されました。
// 出力されたJavaScriptはプレイグラウンド右側の
// ".JS"タブで確認できます。

import { useState } from "react";

export function ExampleApp() {
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}

// 以下は、主な変更点の抜粋です:
//
// - React識別子の代わりとなる関数が、`import`を介して提供される
// - 単一要素(jsx)と複数の子要素(jsxs)にそれぞれ異なる関数が使用される
// - keyがpropsから切り離される
//
// 上記の変更が実装されているRFCは以下で読むことができます:
// https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md

// こうした変更のほとんどは内部的なものであり、
// エンドユーザーがJSXのコードを記述することに
// 影響はありません。
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//// { compiler: { ts: "4.1.0-beta" } }

// 4.1では、TypeScriptとJavaScriptファイルの両方で
// 使われているTypeScriptのJSDocパーサが
// @seeパラメータをサポートします。

// @seeを使えば、クリック(cmd/ctrl + クリック)するか、
// あるいはマウスをホバーした時に表示される情報から
// 関連するコードに素早くアクセスすることができます。

/**
* @see hello
*/
const goodbye = "Good";

/**
* You say hi, I say low
*
* @see goodbye
*/
const hello = "Hello, hello";
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//// { compiler: { ts: "4.1.0-dev.20201028" } }

// TypeScriptでは、すでに厳密な文字列/数値をリテラルとして
// 扱うことができます。例えば、次の関数は厳密な文字列を
// 2つだけ許可し、それ以外は許可しません。

declare function enableFeature(command: "redesign" | "newArtistPage"): void;
enableFeature("redesign");
enableFeature(`newArtistPage`);
enableFeature("newPaymentSystem");

// 文字列リテラルはES2020で記述できるすべての文字列の記述方法をサポートしています。
// さらに、TypeScript 4.1では、サポートを拡張し、
// テンプレート文字列リテラルへの文字列挿入ができるようになりました。

type Features = "Redesign" | "newArtistPage";

// 次の型は上記のUnion型であるFeaturesを使用し、
// Union型の各要素を変換して文字列の後ろに`-branch`を追加します。
type FeatureBranch = `${Features}-branch`;

// 4.1では、文字列を操作するためにテンプレートリテラル内で使用できる
// ジェネリクスのような新しいキーワードのセットをサポートしています。
// そのキーワードとは、Uppercase、Lowercase、Capitalize、Uncapitalizeです。

type FeatureID = `${Lowercase<Features>}-id`;
type FeatureEnvVar = `${Uppercase<Features>}-ID`;

// Union型を構成する文字列は掛け合わされます。
// したがって、複数のUnion型を使用した場合、Union型を構成するそれぞれの型は、
// 他のUnion型を構成するそれぞれの型に対して評価されます。

type EnabledStates = "enabled" | "disabled";
type FeatureUIStrings = `${Features} is ${EnabledStates}`;

// このことにより、それぞれのUnion型の要素の
// すべての可能な組み合わせが考慮されることが保証されます。

// 次の型では、インデックスシグネチャと併用することで
// プロパティキーのリストを素早く作成することができます。

type SetFeatures = {
[K in FeatureID]: boolean
};

// テンプレートリテラルについて続けて学ぶ場合はこちらを参照してください:
// example:mapped-types-with-template-literals

// もしくはこちらの告知ブログ記事をご覧ください:
// https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#template-literal-types
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//// { compiler: { ts: "4.1.0-dev.20201028" } }

// TypeScript 4.1では、テンプレートリテラルがサポートされました。
// テンプレートリテラルの基本はexample:intro-to-template-literalsで学ぶことができます。

// また、Mapped Type宣言に新しい構文が4.1で追加されました。
// これにより、"as `templated string`"の形で
// Union型の文字列変換ができるようになります。

// 例えば、次の型は既存の型のすべてのプロパティを
// 従来のRESTの呼び出しに対応する4つの関数に変換します。

// 各APIのエンドポイントを記述するための文字列のテンプレートリテラル:
type GET<T extends string> = `get${Capitalize<T>}`
type POST<T extends string> = `post${Capitalize<T>}`
type PUT<T extends string> = `put${Capitalize<T>}`
type DELETE<T extends string> = `delete${Capitalize<T>}`

// 上記のリテラル型のUnion
type REST<T extends string> = GET<T> | POST<T> | PUT<T> | DELETE<T>

// 型を引数に取り、その型にあるそれぞれの文字列プロパティに対して、
// 上記のREST型をマッピングし、4つの関数を作成します。

type RESTify<Type> = {
[Key in keyof Type as REST<Key extends string ? Key : never>]: () => Type[Key]
};

// オブジェクトのキーは文字列、数値、シンボルをとりうるため、
// `Key extends string ? Key : never`が必要になります。
// これにより、この型はキーが文字列のケースのみを扱うことができます。

// 次に、APIから利用可能なオブジェクトのリストを作ります:

interface APIs {
artwork: { id: string, title: string};
artist: { id: string, name: string};
location: { id: string, address: string, country: string }
}

// そして、上記の型を使用するオブジェクトを宣言します:
declare const api: RESTify<APIs>

// そうすると、下記の関数がすべて自動的に作成されます
api.getArtist()
api.postArtist()
api.putLocation()

// テンプレートリテラルについて続けて詳しく学びたい場合は以下を参照してください:
// example:string-manipulation-with-template-literals

// もしくは告知ブログ記事をご覧ください:
// https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#template-literal-types

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//// { compiler: { ts: "4.1.0-dev.20201028" } }

// 文字列リテラル型を抽出し操作するためにテンプレートリテラルを使用することができます。
// そのようにして抽出した文字列リテラル型は、今度はプロパティとして使用することができ、
// それにより、API内で文字列からのオブジェクトへと変換するための記述が可能になります。

// ## オブジェクトへの文字列の分割

// テンプレートリテラルは、あるパターンを"分割点"として使用して、
// その間の部分文字列を推測することができます。例えば...

// 次の型はセマンティクスバージョニングに準拠した文字列リテラルです。
type TSVersion = "4.1.2"

// この文字列を構成する要素を抽出する型を作ることができます。
// 2つの'.'を中間点として、文字列を分割してみましょう。
type ExtractSemver<SemverString extends string> =
SemverString extends `${infer Major}.${infer Minor}.${infer Patch}` ?
{ major: Major, minor: Minor, patch: Patch } : { error: "Cannot parse semver string" }

// 1行目は次のexampleを見たことがあるならば、なじみがあるでしょう:
// example:intro-to-template-literals / example:mapped-types-with-template-literals

// 2行目はConditional Typeで、TypeScriptはSemverStringパラメータに対して
// inferをつかったこのパターンが一致するかどうかを検証します。

// 3行目はConditional Typeの結果です。条件が真ならば、それぞれのポジションに渡された
// 部分文字列をもつオブジェクトを返します。
// 文字列がパターンに一致しないならば、エラーメッセージをもつオブジェクトの型を返します。

type TS = ExtractSemver<TSVersion>

// この型はセマンティクスバージョニングを100%サポートしているわけではありません。例えば、次の例を見てみましょう:
type BadSemverButOKString = ExtractSemver<"4.0.Four.4444">

// 一方で、ExtractSemverではそのフォーマットに一致しない文字列はエラーになります。
// このケースでは文字列が"X.Y.Z"というフォーマットである場合のみマッチします。次の行はそうなっていないため、マッチしません:
type SemverError = ExtractSemver<"Four point Zero point Five">

// ## 再帰的な文字列分割

// 前述の例は厳密にマッチする文字列の場合には動作します。しかし、
// もっとあいまいなケースではTypeScript 4.0の機能example:variadic-tuplesを利用したい場合があるでしょう。

// 文字列を再利用可能な要素に分割するとき、タプルを使えばうまく結果を追跡できます。
// Split型の例を次に示します:

type Split<S extends string, D extends string> =
string extends S ? string[] :
S extends '' ? [] :
S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] : [S];

// 1行目は2つのパラメータを宣言しています。ここでは簡潔にするため、1文字を使います。
// Sは分割したい文字列を、Dは区切り文字を表します。
// この行で、これら2つのパラメータが確実に文字列であることを保証します。

// 2行目は入力文字列から一般的な文字列に拡張できるか検証して、文字列がリテラルかどうかをチェックします。
// もしそうならば、文字列の配列を返します。
// リテラルではない文字列を扱うことができないためです。

// 例: 次のようなケース:
type S1 = Split<string, ".">

// 3行目は文字列が空かどうかをチェックし、もしそうならば空のタプルを返します。
type S2 = Split<"", ".">

// 4行目には、ExtractSemverと同様のチェックがあります。
// 入力文字列が`[接頭辞(T)][区切り文字][接尾辞(U)]`にマッチする場合は、
// 接頭辞(T)をタプルの最初のパラメータとして抽出します。次に、接尾辞(U)に対してSplitを再実行して、
// 複数回のマッチに対応できるようにします。
//
// 入力文字列に区切り文字が含まれていない場合は、
// 引数(S)として渡された文字列を含む、長さ1のタプルを返します。

// シンプルなケース
type S3 = Split<"1.2", ".">

// すべての.で分割するために一度再帰呼び出しを行うケース
type S4 = Split<"1.2.3", ".">

// この知識があれば、かなりの数のテンプレートリテラルのコミュニティの例を読んで
// 理解できるようになるはずです。例えば:
//
// - Dan Vanderkamによる、express route extractor
// https://twitter.com/danvdk/status/1301707026507198464
//
// - Mike Ryanによる、document.querySelectorの定義
// https://twitter.com/mikeryandev/status/1308472279010025477
//
// テンプレート文字列リテラルを使った非常に複雑な
// 文字列パーサの実験も行われています。面白い試みですが、
// 本番のコードベースで使用することは推奨されていません。
//
// https://github.com/ghoullier/awesome-template-literal-types
//
// また、告知ブログ記事もご覧ください:
// https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#template-literal-types