or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composite.mdconstraints.mdcontracts.mdindex.mdliterals.mdprimitives.mdresults.mdtemplates.mdunion-intersect.mdutilities.mdvalidation.md

templates.mddocs/

0

# Template Literals

1

2

Validates template literal strings with typed interpolation. Template runtypes allow validation of strings that follow specific patterns with variable parts validated by their own runtypes.

3

4

## Capabilities

5

6

### Template

7

8

Creates a validator for template literal strings with interpolated runtypes.

9

10

```typescript { .api }

11

/**

12

* Creates a validator for template literal strings with typed interpolation

13

* @param strings - String literal parts of the template

14

* @param runtypes - Runtypes for interpolated values

15

* @example Template(['Hello ', '!'], String).check("Hello World!") // "Hello World!"

16

* @example Template("user_", Number).check("user_123") // "user_123"

17

*/

18

function Template<A extends readonly [string, ...string[]], B extends readonly Runtype<LiteralValue>[]>(

19

strings: A,

20

...runtypes: B

21

): TemplateRuntype<A, B>;

22

23

// Alternative call signature for convenience

24

function Template<A extends readonly (LiteralValue | Runtype<LiteralValue>)[]>(

25

...args: A

26

): TemplateRuntype<ExtractStrings<A>, ExtractRuntypes<A>>;

27

28

interface TemplateRuntype<A, B> extends Runtype<TemplateType<A, B>> {

29

tag: "template";

30

strings: A;

31

runtypes: B;

32

}

33

34

type LiteralValue = undefined | null | boolean | number | bigint | string;

35

```

36

37

**Usage Examples:**

38

39

```typescript

40

import { Template, String, Number, Literal, Union } from "runtypes";

41

42

// Basic template validation

43

const Greeting = Template("Hello ", String, "!");

44

const greeting = Greeting.check("Hello World!"); // "Hello World!"

45

46

// ID patterns

47

const UserId = Template("user_", Number);

48

const PostId = Template("post_", String);

49

50

const userId = UserId.check("user_123"); // "user_123"

51

const postId = PostId.check("post_abc123"); // "post_abc123"

52

53

// Multiple interpolations

54

const LogEntry = Template("[", String, "] ", String, ": ", String);

55

const log = LogEntry.check("[INFO] 2024-01-01: Application started");

56

57

// Array-style syntax (for better type inference)

58

const VersionString = Template(["v", "."], Number, Number);

59

const version = VersionString.check("v1.2"); // "v1.2"

60

```

61

62

### URL and Path Patterns

63

64

```typescript

65

import { Template, String, Number, Union, Literal } from "runtypes";

66

67

// API endpoint patterns

68

const UserEndpoint = Template("/api/users/", Number);

69

const PostEndpoint = Template("/api/posts/", String, "/comments/", Number);

70

71

// Validate API paths

72

const userPath = UserEndpoint.check("/api/users/123");

73

const commentPath = PostEndpoint.check("/api/posts/my-post/comments/456");

74

75

// File path patterns

76

const ImagePath = Template("images/", String, ".", Union(Literal("jpg"), Literal("png"), Literal("gif")));

77

const imagePath = ImagePath.check("images/avatar.jpg");

78

79

// Query string patterns

80

const SearchQuery = Template("q=", String, "&page=", Number);

81

const query = SearchQuery.check("q=javascript&page=2");

82

```

83

84

### CSS and Styling Patterns

85

86

```typescript

87

import { Template, Number, String, Union, Literal } from "runtypes";

88

89

// CSS values

90

const PixelValue = Template(Number, "px");

91

const PercentValue = Template(Number, "%");

92

const EmValue = Template(Number, "em");

93

94

const CSSSize = Union(PixelValue, PercentValue, EmValue);

95

96

const width = PixelValue.check("100px"); // "100px"

97

const height = PercentValue.check("50%"); // "50%"

98

99

// Color patterns

100

const HexColor = Template("#", String); // Simplified - would need constraint for valid hex

101

const RgbColor = Template("rgb(", Number, ", ", Number, ", ", Number, ")");

102

103

const color1 = HexColor.check("#ff0000");

104

const color2 = RgbColor.check("rgb(255, 0, 0)");

105

106

// CSS class patterns

107

const BemClass = Template(String, "__", String, "--", String);

108

const bemClass = BemClass.check("button__text--highlighted");

109

```

110

111

### Date and Time Patterns

112

113

```typescript

114

import { Template, Number, String } from "runtypes";

115

116

// ISO date pattern (simplified)

117

const ISODate = Template(Number, "-", Number, "-", Number, "T", Number, ":", Number, ":", Number, "Z");

118

const timestamp = ISODate.check("2024-01-15T14:30:45Z");

119

120

// Custom date formats

121

const DateSlash = Template(Number, "/", Number, "/", Number);

122

const DateDash = Template(Number, "-", Number, "-", Number);

123

124

const date1 = DateSlash.check("12/31/2024");

125

const date2 = DateDash.check("2024-12-31");

126

127

// Time patterns

128

const TimeHM = Template(Number, ":", Number);

129

const TimeHMS = Template(Number, ":", Number, ":", Number);

130

131

const time1 = TimeHM.check("14:30");

132

const time2 = TimeHMS.check("14:30:45");

133

```

134

135

### Configuration and Environment Patterns

136

137

```typescript

138

import { Template, String, Number, Boolean } from "runtypes";

139

140

// Environment variable patterns

141

const DatabaseUrl = Template("postgresql://", String, ":", String, "@", String, ":", Number, "/", String);

142

const dbUrl = DatabaseUrl.check("postgresql://user:pass@localhost:5432/mydb");

143

144

// Configuration keys

145

const ConfigKey = Template("app.", String, ".", String);

146

const configKey = ConfigKey.check("app.database.host");

147

148

// Log levels with context

149

const LogLevel = Template("[", String, "] ", String);

150

const logEntry = LogLevel.check("[ERROR] Database connection failed");

151

```

152

153

## Advanced Template Patterns

154

155

### Nested Templates

156

157

```typescript

158

import { Template, String, Number, Union } from "runtypes";

159

160

// Combine templates for complex patterns

161

const Protocol = Union(Literal("http"), Literal("https"));

162

const Domain = Template(String, ".", String); // simplified domain pattern

163

const Url = Template(Protocol, "://", Domain, "/", String);

164

165

const url = Url.check("https://example.com/path");

166

167

// Reusable template components

168

const Prefix = Template("prefix_", String);

169

const Suffix = Template(String, "_suffix");

170

const Combined = Template(Prefix, "_", Suffix);

171

```

172

173

### Dynamic Validation with Templates

174

175

```typescript

176

import { Template, String, Number, Union, Literal } from "runtypes";

177

178

// API version patterns

179

const ApiV1 = Template("/api/v1/", String);

180

const ApiV2 = Template("/api/v2/", String);

181

const ApiPath = Union(ApiV1, ApiV2);

182

183

// Resource patterns with actions

184

const Action = Union(Literal("create"), Literal("read"), Literal("update"), Literal("delete"));

185

const ResourceAction = Template("/api/", String, "/", Action);

186

187

const resourcePath = ResourceAction.check("/api/users/create");

188

189

// Multi-tenant patterns

190

const TenantResource = Template("/tenant/", String, "/", String, "/", Number);

191

const tenantPath = TenantResource.check("/tenant/acme/users/123");

192

```

193

194

### Template with Constraints

195

196

```typescript

197

import { Template, String, Number, Constraint } from "runtypes";

198

199

// Email pattern (simplified)

200

const EmailLocal = String.withConstraint(s => s.length > 0 && !s.includes("@"));

201

const EmailDomain = String.withConstraint(s => s.includes("."));

202

const Email = Template(EmailLocal, "@", EmailDomain);

203

204

const email = Email.check("user@example.com");

205

206

// Phone number pattern

207

const AreaCode = Number.withConstraint(n => n >= 100 && n <= 999);

208

const PhoneNumber = Template("(", AreaCode, ") ", Number, "-", Number);

209

210

const phone = PhoneNumber.check("(555) 123-4567");

211

212

// Social security number pattern

213

const SSN = Template(Number, "-", Number, "-", Number);

214

const SsnWithConstraints = SSN.withConstraint(ssn => {

215

const parts = ssn.split("-");

216

return parts[0].length === 3 && parts[1].length === 2 && parts[2].length === 4;

217

});

218

```

219

220

### Template Parsing and Transformation

221

222

```typescript

223

import { Template, String, Number, Parser } from "runtypes";

224

225

// Parse template results into structured data

226

const VersionTemplate = Template("v", Number, ".", Number, ".", Number);

227

const VersionParser = VersionTemplate.withParser(versionString => {

228

const match = versionString.match(/v(\d+)\.(\d+)\.(\d+)/);

229

return {

230

major: parseInt(match![1]!),

231

minor: parseInt(match![2]!),

232

patch: parseInt(match![3]!)

233

};

234

});

235

236

const version = VersionParser.parse("v1.2.3");

237

// { major: 1, minor: 2, patch: 3 }

238

239

// Coordinate parsing

240

const CoordinateTemplate = Template("(", Number, ",", Number, ")");

241

const CoordinateParser = CoordinateTemplate.withParser(coordString => {

242

const match = coordString.match(/\(([^,]+),([^)]+)\)/);

243

return {

244

x: parseFloat(match![1]!),

245

y: parseFloat(match![2]!)

246

};

247

});

248

249

const coord = CoordinateParser.parse("(10.5,20.3)");

250

// { x: 10.5, y: 20.3 }

251

```

252

253

## Template Limitations and Workarounds

254

255

### Greedy Matching

256

257

```typescript

258

import { Template, String, Constraint } from "runtypes";

259

260

// Problem: String runtypes are greedy and match too much

261

// Template(String, String) creates pattern ^(.*)(.*)$ where first .* wins all

262

263

// Solution: Use constraints for specific patterns

264

const WordBoundary = String.withConstraint(s => /^\w+$/.test(s));

265

const TwoWords = Template(WordBoundary, " ", WordBoundary);

266

267

const twoWords = TwoWords.check("hello world");

268

269

// Or use more specific runtypes

270

const AlphaString = String.withConstraint(s => /^[a-zA-Z]+$/.test(s));

271

const NumericString = String.withConstraint(s => /^\d+$/.test(s));

272

const AlphaNumeric = Template(AlphaString, NumericString);

273

```

274

275

### Complex Patterns

276

277

```typescript

278

import { Constraint, String } from "runtypes";

279

280

// For very complex patterns, use single constraint instead of template

281

const ComplexPattern = String.withConstraint(s => {

282

// Custom validation logic for complex patterns

283

const regex = /^[A-Z]{2}\d{4}[A-Z]{2}$/;

284

return regex.test(s) || "Must match pattern: 2 letters, 4 digits, 2 letters";

285

});

286

287

const code = ComplexPattern.check("AB1234CD");

288

```