or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aliases-guards.mdflow-utilities.mdindex.mdmapped-types.md

flow-utilities.mddocs/

0

# Flow-style Utilities

1

2

Flow-style utilities provide TypeScript equivalents of Flow.js utility types, enabling easy migration from Flow to TypeScript and maintaining compatibility with Flow-based codebases.

3

4

## Import

5

6

```typescript

7

import {

8

$Keys, $Values, $ReadOnly, $Diff, $PropertyType, $ElementType,

9

$Call, $Shape, $NonMaybeType, Class, mixed

10

} from 'utility-types';

11

```

12

13

## Key Extraction

14

15

### $Keys

16

17

Get the union type of all keys in an object type.

18

19

```typescript { .api }

20

type $Keys<T extends object> = keyof T;

21

```

22

23

**Usage:**

24

25

```typescript

26

interface User {

27

id: number;

28

name: string;

29

email: string;

30

}

31

32

type UserKeys = $Keys<User>;

33

// Result: "id" | "name" | "email"

34

35

// Use with conditional types

36

type StringKeys<T> = {

37

[K in $Keys<T>]: T[K] extends string ? K : never;

38

}[keyof T];

39

40

type UserStringKeys = StringKeys<User>;

41

// Result: "name" | "email"

42

```

43

44

### $Values

45

46

Get the union type of all values in an object type.

47

48

```typescript { .api }

49

type $Values<T extends object> = T[keyof T];

50

```

51

52

**Usage:**

53

54

```typescript

55

interface StatusCodes {

56

OK: 200;

57

NOT_FOUND: 404;

58

SERVER_ERROR: 500;

59

}

60

61

type StatusCode = $Values<StatusCodes>;

62

// Result: 200 | 404 | 500

63

64

interface User {

65

id: number;

66

name: string;

67

active: boolean;

68

}

69

70

type UserValueTypes = $Values<User>;

71

// Result: number | string | boolean

72

```

73

74

## Property Access

75

76

### $PropertyType

77

78

Get the type of a specific property in an object.

79

80

```typescript { .api }

81

type $PropertyType<T extends object, K extends keyof T> = T[K];

82

```

83

84

**Usage:**

85

86

```typescript

87

interface User {

88

id: number;

89

profile: {

90

name: string;

91

avatar: string;

92

};

93

}

94

95

type UserId = $PropertyType<User, 'id'>;

96

// Result: number

97

98

type UserProfile = $PropertyType<User, 'profile'>;

99

// Result: { name: string; avatar: string; }

100

101

// Useful for extracting nested types

102

type ProfileName = $PropertyType<UserProfile, 'name'>;

103

// Result: string

104

```

105

106

### $ElementType

107

108

Get the type of elements at a given index in an array, tuple, or object.

109

110

```typescript { .api }

111

type $ElementType<T extends { [P in K & any]: any }, K extends keyof T | number> = T[K];

112

```

113

114

**Usage:**

115

116

```typescript

117

// With arrays

118

type StringArray = string[];

119

type ArrayElement = $ElementType<StringArray, number>;

120

// Result: string

121

122

// With tuples

123

type UserTuple = [number, string, boolean];

124

type FirstElement = $ElementType<UserTuple, 0>;

125

// Result: number

126

type SecondElement = $ElementType<UserTuple, 1>;

127

// Result: string

128

129

// With objects (same as $PropertyType)

130

interface Config {

131

timeout: number;

132

retries: number;

133

}

134

type TimeoutType = $ElementType<Config, 'timeout'>;

135

// Result: number

136

```

137

138

## Type Transformations

139

140

### $ReadOnly

141

142

Create a deeply readonly version of an object type.

143

144

```typescript { .api }

145

type $ReadOnly<T extends object> = DeepReadonly<T>;

146

```

147

148

**Usage:**

149

150

```typescript

151

interface Settings {

152

theme: {

153

mode: 'light' | 'dark';

154

colors: string[];

155

};

156

user: {

157

name: string;

158

preferences: { [key: string]: any };

159

};

160

}

161

162

type ReadonlySettings = $ReadOnly<Settings>;

163

// Result: All properties and nested properties become readonly

164

// {

165

// readonly theme: {

166

// readonly mode: 'light' | 'dark';

167

// readonly colors: readonly string[];

168

// };

169

// readonly user: {

170

// readonly name: string;

171

// readonly preferences: { readonly [key: string]: any };

172

// };

173

// }

174

175

// Usage in function parameters

176

function processSettings(settings: $ReadOnly<Settings>) {

177

// settings.theme.mode = 'dark'; // Error: Cannot assign to readonly property

178

console.log(settings.theme.mode); // OK: reading is allowed

179

}

180

```

181

182

### $Diff

183

184

Get the set difference of two object types (properties in T but not in U).

185

186

```typescript { .api }

187

type $Diff<T extends U, U extends object> = Pick<T, SetComplement<keyof T, keyof U>>;

188

```

189

190

**Usage:**

191

192

```typescript

193

interface AllProps {

194

name: string;

195

age: number;

196

email: string;

197

password: string;

198

}

199

200

interface PublicProps {

201

name: string;

202

age: number;

203

email: string;

204

}

205

206

type PrivateProps = $Diff<AllProps, PublicProps>;

207

// Result: { password: string; }

208

209

// Common pattern: removing default props

210

interface ComponentProps {

211

title: string;

212

color: string;

213

size: 'small' | 'medium' | 'large';

214

onClick: () => void;

215

}

216

217

interface DefaultProps {

218

color: string;

219

size: 'small' | 'medium' | 'large';

220

}

221

222

type RequiredProps = $Diff<ComponentProps, DefaultProps>;

223

// Result: { title: string; onClick: () => void; }

224

```

225

226

### $Shape

227

228

Make all properties in an object type optional (equivalent to Partial).

229

230

```typescript { .api }

231

type $Shape<T extends object> = Partial<T>;

232

```

233

234

**Usage:**

235

236

```typescript

237

interface User {

238

id: number;

239

name: string;

240

email: string;

241

}

242

243

type PartialUser = $Shape<User>;

244

// Result: { id?: number; name?: string; email?: string; }

245

246

// Useful for update operations

247

function updateUser(id: number, updates: $Shape<User>) {

248

// Can pass any subset of User properties

249

}

250

251

updateUser(1, { name: 'Alice' }); // Valid

252

updateUser(2, { email: 'bob@example.com', name: 'Bob' }); // Valid

253

updateUser(3, {}); // Valid

254

```

255

256

### $NonMaybeType

257

258

Remove null and undefined from a type.

259

260

```typescript { .api }

261

type $NonMaybeType<T> = NonNullable<T>;

262

```

263

264

**Usage:**

265

266

```typescript

267

type MaybeString = string | null | undefined;

268

type DefiniteString = $NonMaybeType<MaybeString>;

269

// Result: string

270

271

type MaybeUser = { name: string; age: number } | null | undefined;

272

type DefiniteUser = $NonMaybeType<MaybeUser>;

273

// Result: { name: string; age: number }

274

275

// Useful in type guards

276

function assertNonMaybe<T>(value: T): asserts value is $NonMaybeType<T> {

277

if (value == null) {

278

throw new Error('Value is null or undefined');

279

}

280

}

281

282

declare const maybeValue: string | null;

283

assertNonMaybe(maybeValue);

284

// maybeValue is now typed as string

285

```

286

287

## Function and Class Types

288

289

### $Call

290

291

Extract the return type from a function type.

292

293

```typescript { .api }

294

type $Call<Fn extends (...args: any[]) => any> = Fn extends (arg: any) => infer RT ? RT : never;

295

```

296

297

**Usage:**

298

299

```typescript

300

function getUserData(id: number): { name: string; email: string } {

301

return { name: 'User', email: 'user@example.com' };

302

}

303

304

type UserData = $Call<typeof getUserData>;

305

// Result: { name: string; email: string }

306

307

// With generic functions

308

function createArray<T>(item: T, count: number): T[] {

309

return Array(count).fill(item);

310

}

311

312

type StringArrayCreator = typeof createArray<string>;

313

type StringArrayResult = $Call<StringArrayCreator>;

314

// Result: string[]

315

316

// Useful for extracting promise types

317

async function fetchUser(id: number): Promise<User> {

318

// ... implementation

319

}

320

321

type FetchUserResult = $Call<typeof fetchUser>;

322

// Result: Promise<User>

323

```

324

325

### Class

326

327

Represent a constructor type for a given instance type.

328

329

```typescript { .api }

330

type Class<T> = new (...args: any[]) => T;

331

```

332

333

**Usage:**

334

335

```typescript

336

class User {

337

constructor(public name: string) {}

338

}

339

340

type UserConstructor = Class<User>;

341

// Result: new (...args: any[]) => User

342

343

// Use in factory functions

344

function createInstance<T>(ctor: Class<T>, ...args: any[]): T {

345

return new ctor(...args);

346

}

347

348

const user = createInstance(User, 'Alice');

349

// user is typed as User

350

351

// With generics

352

class Repository<T> {

353

constructor(private items: T[] = []) {}

354

355

add(item: T): void {

356

this.items.push(item);

357

}

358

}

359

360

type StringRepository = Repository<string>;

361

type StringRepositoryConstructor = Class<StringRepository>;

362

```

363

364

## Flow Compatibility

365

366

### mixed

367

368

Equivalent to TypeScript's `unknown` type for Flow compatibility.

369

370

```typescript { .api }

371

type mixed = unknown;

372

```

373

374

**Usage:**

375

376

```typescript

377

// When migrating from Flow

378

function processValue(value: mixed): string {

379

// Must use type guards to narrow the type

380

if (typeof value === 'string') {

381

return value.toUpperCase();

382

}

383

if (typeof value === 'number') {

384

return value.toString();

385

}

386

return 'unknown';

387

}

388

389

// Prefer unknown in new TypeScript code

390

function processValueTS(value: unknown): string {

391

// Same implementation as above

392

}

393

```

394

395

## Migration Examples

396

397

### From Flow to TypeScript

398

399

```typescript

400

// Flow code:

401

// type UserKeys = $Keys<User>;

402

// type UserValues = $Values<User>;

403

// type ReadonlyUser = $ReadOnly<User>;

404

405

// TypeScript with utility-types:

406

import { $Keys, $Values, $ReadOnly } from 'utility-types';

407

408

type UserKeys = $Keys<User>;

409

type UserValues = $Values<User>;

410

type ReadonlyUser = $ReadOnly<User>;

411

412

// Gradually migrate to native TypeScript equivalents:

413

type UserKeysNative = keyof User;

414

type UserValuesNative = User[keyof User];

415

type ReadonlyUserNative = DeepReadonly<User>;

416

```