(FRONT) FRONT (2022)

( << Back) TypeManipulation.ts

   1:  console.log(`
   2:  --- 1 --- Creating Types from Types  https://www.typescriptlang.org/docs/handbook/2/types-from-types.html 
   3:  `)
   4:   
   5:  //Generics - Types which take parameters
   6:  //Keyof Type Operator - Using the keyof operator to create new types
   7:  //Typeof Type Operator - Using the typeof operator to create new types
   8:  //Indexed Access Types - Using Type['a'] syntax to access a subset of a type
   9:  //Conditional Types - Types which act like if statements in the type system
  10:  //Mapped Types - Creating types by mapping each property in an existing type
  11:  //Template Literal Types - Mapped types which change properties via template literal strings
  12:   
  13:  console.log(`
  14:  --- 1 --- note about Keyof
  15:  `)
  16:   
  17:  //https://www.typescriptlang.org/docs/handbook/2/keyof-types.html
  18:   
  19:  type Point = { x: number; y: number };
  20:  type P = keyof Point;
  21:  //The following type P is the same type as type P = "x" | "y"
  22:   
  23:  type Mapish = { [k: string]: boolean };
  24:  type M = keyof Mapish;
  25:  //M is string | number — this is because JavaScript object keys are always coerced to a string, so obj[0] is always the same as obj["0"]
  26:   
  27:  let k1: M = "1";
  28:  let k2: M = 1
  29:  console.log(k1, k2)
  30:   
  31:  console.log(`
  32:  --- 2 --- js typeOf
  33:  `)
  34:  //https://www.typescriptlang.org/docs/handbook/2/typeof-types.html
  35:   
  36:   
  37:  //JavaScript already has a typeof operator you can use in an expression context, TypeScript adds a typeof operator you can use in a type context 
  38:  let chars = "111"
  39:  let ns: typeof chars = '111'
  40:  console.log(ns)
  41:   
  42:  // simple onplace type declaration
  43:  let P1: () => {
  44:      x: number;
  45:      y: number
  46:  } = () => ({
  47:      x: 5,
  48:      y: 10
  49:  })
  50:   
  51:  // the same declaration with type
  52:  function fn() {
  53:      return { x: 10, y: 3 };
  54:  }
  55:   
  56:  type Pn = typeof fn;
  57:  let P2: Pn = () => ({
  58:      x: 5,
  59:      y: 10
  60:  })
  61:   
  62:  //ReturnType
  63:  type Pm = ReturnType<typeof fn>;
  64:  let P3: Pm = { x: 1, y: 2 }
  65:   
  66:  console.log(P1(), P2(), P3)
  67:   
  68:   
  69:  console.log(`
  70:  --- 3 --- Indexed Access Types
  71:  `)
  72:   
  73:  type Person1 = { age: number; name: string; alive: boolean };
  74:  type Age1 = Person1["age"];
  75:   
  76:  let P4: Age1 = 10
  77:  console.log(P4)
  78:   
  79:  const MyArray1 = [
  80:      { name: "Alice", age: 15 },
  81:      { name: "Bob", age: 23 },
  82:      { name: "Eve", age: 38 },
  83:  ];
  84:   
  85:  type Person2 = typeof MyArray1[number];
  86:   
  87:  type Age2 = typeof MyArray1[number]["age"];
  88:   
  89:  type Age3 = Person2["age"];
  90:   
  91:  let P5: Person2 = { name: "A", age: 1 }
  92:  let P6: Age2 = 1
  93:  let P7: Age3 = 2
  94:   
  95:  console.log(P5, P6, P7)
  96:   
  97:  console.log(`
  98:  --- 4 --- Conditional Types ( SomeType extends OtherType ? TrueType : FalseType; )
  99:  `)
 100:   
 101:  interface IdLabel {
 102:      id: number /* some fields */;
 103:  }
 104:  interface NameLabel {
 105:      name: string /* other fields */;
 106:  }
 107:   
 108:  //overloading function
 109:  function createLabel1(id: number): IdLabel;
 110:  function createLabel1(name: string): NameLabel;
 111:  function createLabel1(nameOrId: string | number): IdLabel | NameLabel;
 112:  function createLabel1(nameOrId: string | number): IdLabel | NameLabel {
 113:      throw "unimplemented";
 114:  }
 115:   
 116:  // the same as below:
 117:  //The extends keyword on an interface allows us to effectively copy members from other named types, and add whatever new members we want
 118:   
 119:  type NameOrId<T extends number | string> = T extends number
 120:      ? IdLabel
 121:      : NameLabel;
 122:   
 123:  function createLabel2<T extends number | string>(idOrName: T): NameOrId<T> {
 124:      throw "unimplemented";
 125:  }
 126:   
 127:  console.log(`
 128:  --- 5 --- Inferring Within Conditional Types
 129:  `)
 130:   
 131:  //https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types
 132:  //we used the infer keyword to declaratively introduce a new generic type variable named Item instead of specifying how to retrieve the element type of Type within the true branch.
 133:  //For example, for simple cases, we can extract the return type out from function types:
 134:   
 135:  type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
 136:      ? Return
 137:      : never;
 138:   
 139:  type Nm = GetReturnType<() => number>;
 140:   
 141:  type Str = GetReturnType<(x: string) => string>;
 142:   
 143:  type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>;
 144:   
 145:  console.log(`
 146:  --- 6 --- Distributive Conditional Types
 147:  `)
 148:  //https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
 149:  //When conditional types act on a generic type, they become distributive when given a union type.
 150:  //If we plug a union type into ToArray, then the conditional type will be applied to each member of that union.
 151:   
 152:  type ToArray<Type> = Type extends any ? Type[] : never;
 153:   
 154:  type StrArrOrNumArr = ToArray<string | number>;
 155:   
 156:  console.log(`
 157:  --- 7 --- Mapped Types
 158:  `)
 159:   
 160:   
 161:  //https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
 162:  //When you don’t want to repeat yourself, sometimes a type needs to be based on another type
 163:  //Mapped types build on the syntax for index signatures,
 164:   
 165:  type OnlyBoolsAndPerson = {
 166:      [key: string]: boolean | Person1;
 167:  };
 168:   
 169:  const conforms: OnlyBoolsAndPerson = {
 170:      del: true,
 171:      rodney: false,
 172:  };
 173:   
 174:  //A mapped type is a generic type which uses a union of PropertyKeys (frequently created via a keyof) to iterate through keys to create a type:
 175:   
 176:  type OptionsFlags<T> = {
 177:      [Property in keyof T]: boolean;
 178:  };
 179:   
 180:  type Features = {
 181:      darkMode: () => void;
 182:      newUserProfile: () => void;
 183:  };
 184:   
 185:  type FeatureOptions = OptionsFlags<Features>;
 186:   
 187:  console.log(`
 188:  --- 8 --- Mapping Modifiers, readonly and ?
 189:  `)
 190:   
 191:  // Removes 'readonly' attributes from a type's properties
 192:  type CreateMutable<Type> = {
 193:      -readonly [Property in keyof Type]: Type[Property];
 194:  };
 195:   
 196:  type LockedAccount = {
 197:      readonly id: string;
 198:      readonly name: string;
 199:  };
 200:   
 201:  type UnlockedAccount = CreateMutable<LockedAccount>;
 202:   
 203:  // Removes 'optional' attributes from a type's properties
 204:  type Concrete<Type> = {
 205:      [Property in keyof Type]-?: Type[Property];
 206:  };
 207:   
 208:  type MaybeUser = {
 209:      id: string;
 210:      name?: string;
 211:      age?: number;
 212:  };
 213:   
 214:  type User = Concrete<MaybeUser>;
 215:   
 216:  console.log(`
 217:  --- 9 --- Key Remapping via as
 218:  `)
 219:   
 220:  type MappedTypeWithNewProperties<T> = {
 221:      [Properties in keyof T as P]: T[Properties]
 222:  }
 223:   
 224:  //You can leverage features like template literal types to create new property names from prior ones
 225:  type Getters<Type> = {
 226:      [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
 227:  };
 228:   
 229:  interface Person {
 230:      name: string;
 231:      age: number;
 232:      location: string;
 233:  }
 234:   
 235:  type LazyPerson = Getters<Person>;
 236:   
 237:   
 238:  //You can map over arbitrary unions, not just unions of string | number | symbol, but unions of any type:
 239:   
 240:  type EventConfig<Events extends { kind: string }> = {
 241:      [E in Events as E["kind"]]: (event: E) => void;
 242:  }
 243:   
 244:  type SquareEvent = { kind: "square", x: number, y: number };
 245:  type CircleEvent = { kind: "circle", radius: number };
 246:   
 247:  type Config = EventConfig<SquareEvent | CircleEvent>
 248:   
 249:   
 250:  console.log(`
 251:  --- 9 --- Template Literal Types
 252:  `)
 253:   
 254:  type World = "world";
 255:   
 256:  type Greeting = `hello ${World}`;
 257:   
 258:  type EmailLocaleIDs = "welcome_email" | "email_heading";
 259:  type FooterLocaleIDs = "footer_title" | "footer_sendoff";
 260:   
 261:  type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
 262:   
 263:  type AllLocaleID = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
 264:  type Lang = "en" | "ja" | "pt";
 265:   
 266:  type LocaleMessageIDs = `${Lang}_${AllLocaleID}`;
 267:   
 268:   
 269:  console.log(`
 270:  --- 10 --- Intrinsic String Manipulation Types : Uppercase<StringType>, Lowercase<StringType>, Capitalize<StringType>, Uncapitalize<StringType>
 271:  `)
 272:   
 273:  type Greeting1 = "Hello, world"
 274:  type ShoutyGreeting = Uppercase<Greeting1>
 275:   
 276:  type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
 277:  type MainID = ASCIICacheKey<"my_app">
 278:   
 279:  console.log(`
 280:  --- 11 --- Intersection Types
 281:  `)
 282:   
 283:  interface Colorful {
 284:      color: string;
 285:  }
 286:  interface Circle {
 287:      radius: number;
 288:  }
 289:   
 290:  type ColorfulCircle = Colorful & Circle;
 291:   
 292:  function draw(circle: Colorful & Circle) {
 293:      console.log(`Color was ${circle.color}`);
 294:      console.log(`Radius was ${circle.radius}`);
 295:  }
 296:   
 297:  // okay
 298:  //draw({ color: "blue", radius: 42 });
 299:   
 300:  console.log(`
 301:  --- 12 --- type aliases, unlike interfaces, can describe more than just object types, we can also use them to write other kinds of generic helper types.
 302:  `)
 303:   
 304:  type OrNull<T> = T | null;
 305:   
 306:  type OneOrMany<T> = T | T[];
 307:   
 308:  type OneOrManyOrNull1<T> = OrNull<OneOrMany<T>>;
 309:   
 310:  type OneOrManyOrNull2<T> = OneOrMany<T> | null
 311:   
 312:  type OneOrManyOrNullStrings1 = OneOrManyOrNull1<string>;
 313:   
 314:  type OneOrManyOrNullStrings2 = OneOrManyOrNull2<string>;
 315:   
 316:  console.log(`
 317:  --- 13 --- Readonly Array Type and readonly tuple type
 318:  `)
 319:   
 320:  function doStuff(values: ReadonlyArray<string>) {
 321:      // We can read from 'values'...
 322:      const copy = values.slice();
 323:      console.log(`The first value is ${values[0]}`);
 324:   
 325:      // ...but we can't mutate 'values'.
 326:      // values.push("hello!");
 327:  }
 328:   
 329:  const roArray: ReadonlyArray<string> = ["red", "green", "blue"];
 330:   
 331:  function doSomething(pair: readonly [string, number]) {
 332:      // ...
 333:    }
 334:   
 335:  console.log(`
 336:  --- 14 --- 
 337:  `)
 338:   
 339:   
 340:   
 341:  console.log(`
 342:  --- 15 --- Template Literal Types examples
 343:  `)
 344:   
 345:  const person = makeWatchedObject({
 346:      firstName: "Saoirse",
 347:      lastName: "Ronan",
 348:      age: 26,
 349:  });
 350:   
 351:  // makeWatchedObject has added `on` to the anonymous Object
 352:  person.on("firstNameChanged", (newValue) => {
 353:      console.log(`firstName was changed to ${newValue}!`);
 354:  });
 355:   
 356:  type PropEventSource<Type> = {
 357:      on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
 358:  };
 359:   
 360:  /// Create a "watched object" with an `on` method, so that you can watch for changes to properties.
 361:  declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;
 362:   
 363:  console.log(`
 364:  --- 16 --- Inference with Template Literals
 365:  `)
 366:  //https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html#inference-with-template-literals
 367:   
 368:  type PropEventSource1<Type> = {
 369:      on<Key extends string & keyof Type>
 370:          (eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void): void;
 371:  };
 372:   
 373:  declare function makeWatchedObject1<Type>(obj: Type): Type & PropEventSource1<Type>;
 374:   
 375:  const person1 = makeWatchedObject1({
 376:      firstName: "Saoirse",
 377:      lastName: "Ronan",
 378:      age: 26
 379:  });
 380:   
 381:  person1.on("firstNameChanged", newName => {
 382:      console.log(`new name is ${newName.toUpperCase()}`);
 383:  });
 384:   
 385:  person1.on("ageChanged", newAge => {
 386:   
 387:      if (newAge < 0) {
 388:          console.warn("warning! negative age");
 389:      }
 390:  })



Front context:



Comments ( )
Link to this page: http://www.vb-net.com/TypescriptLearningStartPoint/TypeManipulation.htm
< THANKS ME>