{"id":17677447,"url":"https://github.com/unadlib/typescript-tutorial","last_synced_at":"2025-05-12T21:29:10.597Z","repository":{"id":44034143,"uuid":"224032010","full_name":"unadlib/typescript-tutorial","owner":"unadlib","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-05T02:23:22.000Z","size":929,"stargazers_count":10,"open_issues_count":12,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-01T03:51:09.217Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unadlib.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-25T20:05:41.000Z","updated_at":"2023-03-08T16:54:02.000Z","dependencies_parsed_at":"2023-02-03T06:01:50.759Z","dependency_job_id":null,"html_url":"https://github.com/unadlib/typescript-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unadlib%2Ftypescript-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unadlib%2Ftypescript-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unadlib%2Ftypescript-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unadlib%2Ftypescript-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unadlib","download_url":"https://codeload.github.com/unadlib/typescript-tutorial/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253824745,"owners_count":21970067,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-24T07:28:42.844Z","updated_at":"2025-05-12T21:29:10.578Z","avatar_url":"https://github.com/unadlib.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Typescript Tutorial\n\n[Generics in TypeScript](https://docs.google.com/presentation/d/1m5112bmfD7_-imhU9xbjgRDQ5k5H6NMpzLQkMaFNHo8/edit?usp=sharing)\n\n## 1. Basics\n\n### 1.1 `unkown` / `any` /`never` / `void` / `undefined` / `null`\n\n`unkown` which is the type-safe counterpart of `any` (TypeScript 3.0).\n\n```ts\n{\n  const any00: { foo: any } = { foo: 10 };\n  const unknown00: {foo: unknown } =  { foo: 10 };\n\n\n  const val1: string = any00.foo;\n  const val2: number = unknown00.foo; // Error\n\n  any00.foo.method();\n  unknown00.foo.method(); // Error\n}\n```\n\n`never` type represents the type of values that never occur, `any` isn’t assignable to `never`.\n\n`any` is any type, but doesn't include `never`. In non-strict mode, it is equivalent to `Object`.\n\n```ts\n{\n  let never00: never;\n  let never01: never;\n  let never02: never;\n\n  let any00: any;\n\n  never01 = never00; // Error\n  any00 = never02; // Error\n}\n\nfunction error(message: string): never {\n  throw new Error(message);\n}\n\nfunction fail() {\n    return error(\"Something failed\");\n}\n\nfunction infiniteLoop(): never {\n    while (true) {\n    }\n}\n```\n\n`void` contains `undefined` and `null` without `--strictNullChecks` flag, when using the `--strictNullChecks` flag, `void` just contains `undefined`.\n\n### 1.2 Object / object / { [K: string]: any } / { [K in string]: any }\n\n`Object` is a type other than `null` and `undefined`, **it has not derivations**.\n\n`object` is a type that represents the non-primitive type.\n\n`{ [K: string]: any }` \u0026 `{ [K in string]: any }` can be type alias, they're equivalent to `object`, **but `object` has not derivations**.\n\n`{ [K in string]: any }` can't be defined as an interface, `{ [K: string]: any }` can also be defined as an interface.\n\n* non-strict mode.\n\n```ts\n{\n  const obj00: Object = { a: 1 };\n  const obj01: Object =  [];\n  const obj02: Object =  Object.create(null);\n  const obj03: Object =  new String('');\n  const obj04: Object =  null;\n  const obj05: Object =  1;\n  const obj06: Object =  '1';\n  const obj07: Object =  () =\u003e {};\n  const obj08: Object =  undefined;\n}\n\n{\n  const obj00: object = { a: 1 };\n  const obj01: object =  [];\n  const obj02: object =  Object.create(null);\n  const obj03: object =  new String('');\n  const obj04: object =  null;\n  const obj05: object =  1; // Error\n  const obj06: object =  '1'; // Error\n  const obj07: object =  () =\u003e {};\n  const obj08: object =  undefined;\n}\n\n```\n\n* strict mode.\n\n```ts\n{\n  const obj00: Object = { a: 1 };\n  const obj01: Object =  [];\n  const obj02: Object =  Object.create(null);\n  const obj03: Object =  new String('');\n  const obj04: Object =  null; // Error\n  const obj05: Object =  1;\n  const obj06: Object =  '1';\n  const obj07: Object =  () =\u003e {};\n  const obj08: Object =  undefined; // Error\n}\n\n{\n  const obj00: object = { a: 1 };\n  const obj01: object =  [];\n  const obj02: object =  Object.create(null);\n  const obj03: object =  new String('');\n  const obj04: object =  null; // Error\n  const obj05: object =  1; // Error\n  const obj06: object =  '1'; // Error\n  const obj07: object =  () =\u003e {};\n  const obj08: object =  undefined; // Error\n}\n```\n\n### 1.3 $Type / $type (string, number, boolean)\n\n`$Type` contains `$type` and `[object $type]`, and `$type` only means itself.\n\nUsually only `$type` type is used (`$type` contains `$type | null | undefined` in non-strict mode).\n\nFor example, `String` and `string`:\n\n```ts\n{\n  const str00: String = 'a';\n  const str01: String = new String('a');\n}\n\n{\n  const str00: string = 'a';\n  const str01: string = new String('a'); // Error\n}\n```\n\n### 1.4 `extends ? :` / `infer` / `extends`\n\n`extends ? :` is commonly used in the generics type inferences, and is often used in conjunction with `infer`.\n\nIf just use `extends`, it is often used for type constraints.\n\n```ts\ntype Foo\u003cT\u003e = T extends string ? never : number;\ntype Foo0 = Foo\u003cboolean\u003e; // number\n\ntype FooBar\u003cT\u003e = T extends { o: infer O } ? O : never;\ntype fooBar0 = FooBar\u003c{ o: { s: string } }\u003e; // { s: string }\n```\n\n### 1.5 `keyof` / `typeof`\n\n`typeof` is a type inference from a value in TypeScript.\n\n`keyof` is used for index type query.\n\n```ts\ntype Foo = { n: number; s: string };\ntype Keys = keyof Foo; // \"n\" | \"s\", union type\n\nconst fn = (s: string) =\u003e (e: string): number =\u003e e.length + s.length;\ntype Fn = typeof fn; // type Fn = (s: string) =\u003e (e: string) =\u003e number\n\nconst obj = {l0: { l1: { l2: 'val' } } };\ntype Obj = typeof obj;\n// type Obj = {\n//     l0: {\n//         l1: {\n//             l2: string;\n//         };\n//     };\n// }\n\nconst arr0 = ['a', 1, null, undefined];\ntype Arr0 = typeof arr0; // type Arr0 = (string | number)[]\n\nconst arr1= ['a', 1, null, undefined, {}];\ntype Arr1 = typeof arr1; // type Arr1 = {}[]\n\nconst func = \u003cT\u003e(t: T): T =\u003e t;\ntype Func = typeof func; // type A = \u003cT\u003e(t: T) =\u003e T\n\nclass A\u003cT\u003e{\n  s: string;\n  t: T;\n  bar(s: string) {\n    return s.length;\n  }\n}\n\nconst a = new A();\ntype A1 = typeof a; // type A1 = A\u003cunknown\u003e\n```\n\n### 1.6 `abstract` / `interface` / `class`\n\n`abstract` and `interface` have constraints without derivations for `class`.\n\n```ts\ninterface Foo {\n  bar: string;\n  foobar(s: string): number; \n}\n\nclass FooClazz implements Foo {\n  bar: string;\n  foobar(s: string): number {\n    throw new Error(\"Method not implemented.\");\n  }\n}\n\nabstract class BarClass {\n  bar: string;\n  abstract foobar(s: string): number;\n}\n\nclass BarClazz extends BarClass {\n  foobar(s: string): number {\n    throw new Error(\"Method not implemented.\");\n  }\n}\n```\n\n### 1.7  Assertions(`!` / `as` / `\u003ctype\u003e` / `const`)\n\n* `!` is non-null assertion operator in TypeScript(`--strictNullChecks` mode).\n\n```ts\nconst a: { foo?: { bar?: { [K: string]: any } } } = {};\nif (a.foo!.bar!.foobar) {}\n```\n\n* Both `as` and `\u003ctype\u003e` are assertion operators, they're equivalent.\n\n**Assertions can only be used for subset relationships.**\n\n```ts\ninterface B { str: string };\nconst b0 = { num: 1 } as B; // Error\nconst b1 = ({ num: 1 } as any) as B;\nconst b2 = \u003cB\u003e({ num: 1 } as any);\nconst b3: B = { num: 1 } as any;\n```\n\n* `const` is a `readonly` or non-expandable assertion operator(TypeScript 3.4).\n\n```ts\nconst c0 = {\n  e: 0,\n  f: 1\n} as const;\nc0.e = 1; // Error\nconst c = \u003cconst\u003e['a', 'b'];\nc[0] = 'f'; // Error\n```\n\n### 1.8 Generics Type Usage\n\n```ts\ntype Foo\u003cT\u003e = T;\ninterface Bar\u003cT\u003e {\n  t: T;\n}\n\nconst fn = \u003cT\u003e(t: T): T =\u003e t; \nclass A\u003cT\u003e {\n  t: T;\n};\nnew A\u003cnumber\u003e();\n\nclass B\u003cT extends {num: number}\u003e extends A\u003cT\u003e {}\nnew B(); // OK\nnew B\u003c{num: number; str: string}\u003e(); // OK\nnew B\u003c{str: string}\u003e(); // Error\nnew B\u003cany\u003e(); // OK\nnew B\u003cnever\u003e(); // OK\nnew B\u003c{[K: string]: any}\u003e(); // Error\n```\n\n### 1.9 Rest elements in tuple types\n\n```ts\nfunction tuple\u003cT extends any[]\u003e(...args: T): T {\n    return args;\n}\n\nconst numbers: number[] = getArrayOfNumbers();\nconst t1 = tuple(\"foo\", 1, true);  // [string, number, boolean]\nconst t2 = tuple(\"bar\", ...numbers);  // [string, ...number[]]\n```\n### 1.10 `is` Operator \n\n```ts\nfunction isString(test: any): test is string {\n  return typeof test === \"string\";\n}\n\nfunction example(foo: any) {\n  if (isString(foo)) {\n    // foo: string\n  }\n}\n```\n\n## 2. Advanced\n\n### 2.1 Overloading \u0026 Merging\n\n// TODO\n\n[https://www.typescriptlang.org/docs/handbook/declaration-merging.html](https://www.typescriptlang.org/docs/handbook/declaration-merging.html\n)\n\n### 2.2 DeepPartial or DeepReadonly\n\n```ts\ntype DeepPartial\u003cT\u003e = {\n  [P in keyof T]?: T[P] extends (infer U)[]\n    ? DeepPartial\u003cU\u003e[]\n    : T[P] extends object\n    ? DeepPartial\u003cT[P]\u003e\n    : T[P]\n};\ntype A = DeepPartial\u003c{\n  a: {\n    b: {\n      e: string;\n    }[]\n  };\n}\u003e\n```\n\n### 2.3 UnionToTuple, TupleToUnion \u0026 UnionToIntersection\n\n* TupletoUnion\n\n```ts\ntype TupletoUnion0\u003cT\u003e = T extends (infer E)[] ? E : T;\ntype TupletoUnion1\u003cT\u003e = T extends { [index: number]: infer E } ? E : never;\ntype A0 = TupletoUnion0\u003c[\"a\", \"b\", number]\u003e;\ntype A1 = TupletoUnion1\u003c[\"a\", \"b\", number]\u003e;\n```\n\n* UnionToTuple\n\n```ts\ntype UnionToIoF\u003cU\u003e = (U extends any\n? (k: (x: U) =\u003e void) =\u003e void\n: never) extends (k: infer I) =\u003e void\n  ? I\n  : never;\ntype UnionPop\u003cU\u003e = UnionToIoF\u003cU\u003e extends { (a: infer A): void } ? A : never;\ntype Prepend\u003cU, T extends any[]\u003e = ((a: U, ...r: T) =\u003e void) extends (\n  ...r: infer R\n) =\u003e void\n  ? R\n  : never;\ntype UnionToTupleRecursively\u003cUnion, Result extends any[]\u003e = {\n  1: Result;\n  0: UnionToTupleRecursively_\u003cUnion, UnionPop\u003cUnion\u003e, Result\u003e;\n}[[Union] extends [never] ? 1 : 0];\n\ntype UnionToTupleRecursively_\u003c\n  Union,\n  Element,\n  Result extends any[]\n\u003e = UnionToTupleRecursively\u003c\n  Exclude\u003cUnion, Element\u003e,\n  Prepend\u003cElement, Result\u003e\n\u003e;\n\ntype UnionToTuple\u003cU\u003e = UnionToTupleRecursively\u003cU, []\u003e;\n\ntype A = UnionToTuple\u003c\"a\" | \"b\" | number\u003e;\n```\n\n* UnionToIntersection\n\n```ts\ntype A = { name: number };\ntype B = { age: number };\n\ntype UnionToIntersection\u003cU\u003e = (U extends any\n? (k: U) =\u003e void\n: never) extends (k: infer I) =\u003e void\n  ? I\n  : never;\ntype Result = UnionToIntersection\u003cA | B\u003e; // A \u0026 B\n```\n\n### 2.3 Covariance \u0026 Contravariance\n\n// TODO\n\n[https://medium.com/@michalskoczylas/covariance-contravariance-and-a-little-bit-of-typescript-2e61f41f6f68](https://medium.com/@michalskoczylas/covariance-contravariance-and-a-little-bit-of-typescript-2e61f41f6f68)\n```ts\n\n```\n\n### 2.4 Recursive Type(TypeScript 3.7)\n\n```ts\ntype Node\u003cT\u003e =\n  | {\n      key: string;\n      value: T;\n      children?: Node\u003cT\u003e[];\n    }\n  | Node\u003cT\u003e[];\n\nconst node: Node\u003cstring\u003e = {\n  key: \"foo0\",\n  value: \"fooValue0\",\n  children: [\n    {\n      key: \"foo1\",\n      value: \"fooValue1\",\n      children: [\n        {\n          key: \"foo2\",\n          value: \"fooValue2\"\n        }\n      ]\n    }\n  ]\n};\n```\n\n## 3. Not Supported Types\n\n* Dependent types\n\n[https://github.com/microsoft/TypeScript/issues/33014](https://github.com/microsoft/TypeScript/issues/33014)\n\n```ts\ninterface F {\n  \"t\": number,\n  \"f\": boolean,\n}\n\nfunction f\u003cT extends \"t\" | \"f\"\u003e(\n  t: T,\n  t2: T, // second key which we do not test\n  ft: F[T], // a value of type F[T]\n  f: F, // a record of type F\n) {\n  if (t === \"t\") {\n      const n: number = ft; // a) should be rejected, ft can be bool\n      f[t2] = 1; // b) should be rejected, f[t2] can be bool\n      return 1; // c) should be accepted\n  }\n  throw \"\";\n}\n```\n\n* Refinement Types\n\n```ts\ntype Foo = {n : number | 0 \u003c n };\n```\n\n* Negated Types\n\n[https://github.com/microsoft/TypeScript/pull/33050](https://github.com/microsoft/TypeScript/pull/33050)\n\n```ts\nconst foo = \u003cT extends not string\u003e(t: T): T =\u003e t;\n```\n\n* writeonly\n\n[https://github.com/microsoft/TypeScript/issues/21759](https://github.com/microsoft/TypeScript/issues/21759)\n\n```ts\ninterface A {\n  readonly prop: boolean;\n}\n\nconst a0: A = {\n  prop: false\n};\n\nconst a1: A = {\n  get prop() {\n      return false;\n  }\n};\n\nconst a2: A = {\n  set prop(value: boolean) {}\n};\n```\n\n```ts\ninterface Bar {\n  readonly foo: string | null;\n  writeonly foo: string | object;\n}\n```\n\n* Width Subtyping\n\n```js\n// @flow\nfunction method(obj: {| foo: string |} | {| bar: number |}) {\n  if (obj.foo) {\n    // obj.foo: string\n  }\n}\n```\n\nWe should use `as` assert in TypeScript for implementation.\n\n```ts\nfunction method(obj: { foo: string } | { bar: number }) {\n  const _obj = (obj as { foo: string });\n  if (_obj.foo) {\n    // obj.foo: string\n  }\n}\n```\n\n* Type Variance\n\n// TODO\n\nInvariance / Covariance / Contravariance / Bivariance\n\n* Opaque Types\n\n// TODO\n\n```ts\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funadlib%2Ftypescript-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funadlib%2Ftypescript-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funadlib%2Ftypescript-tutorial/lists"}