Skip to content

Latest commit

History

History
191 lines (155 loc) 路 3.9 KB

readme.md

File metadata and controls

191 lines (155 loc) 路 3.9 KB

literal

Back to root readme.md

This function uses the rulr.isLiteral guard to check the input matches a literal as shown in the example below. It should only throw rulr.InvalidLiteralError. If rulr.literal doesn't give you an accurate enough type, you can use rulr.constant.

import * as rulr from 'rulr'

enum TrafficLight {
	Red,
	Amber,
	Green,
}

const constrainToExample = rulr.object({
	required: {
		example: rulr.literal(TrafficLight.Red as const),
	},
})

type Example = rulr.Static<typeof constrainToExample>
// {
//   example: TrafficLight.Red
// }

// Valid
const example1: Example = constrainToExample({
	example: TrafficLight.Red,
})

// Invalid
const example2: Example = constrainToExample({
	example: TrafficLight.Amber,
})

This rule is especially useful if you want to write code like the following.

import * as rulr from 'rulr'

enum TrafficLight {
	Red,
	Amber,
	Green,
}

const constrainToExample = rulr.object({
	required: {
		example: rulr.literal(TrafficLight.Red as const),
	},
})

type Example = rulr.Static<typeof constrainToExample>
// {
//   example: TrafficLight.Red
// }

// This part is actually valid, no need to run the validator function.
const example1: Example = {
	example: TrafficLight.Red,
}

Note how this is different to rulr.constant

import * as rulr from 'rulr'

enum TrafficLight {
	Red,
	Amber,
	Green,
}

const constrainToRedLight = rulr.constant(Symbol(), TrafficLight.Red)

const constrainToExample = rulr.object({
	required: {
		example: constrainToRedLight,
	},
})

type Example = rulr.Static<typeof constrainToExample>
// {
//   example: rulr.Constraint<typeof exampleSymbol, TrafficLight>
// }

// Invalid according to the compiler.
const example1: Example = {
	example: TrafficLight.Red,
}

// Valid according to the compiler.
const example2: Example = constrainToExample({
	example: TrafficLight.Red,
})

// Valid according to the compiler.
const example3: Example = {
	example: constrainToRedLight(TrafficLight.Red),
}

This issue is especially noticeable when you combine rulr.constant with rulr.union as shown below.

import * as rulr from 'rulr'

enum TrafficLight {
	Red,
	Amber,
	Green,
}

const constrainToRedLight = rulr.constant(Symbol(), TrafficLight.Red)
const constrainToGreenLight = rulr.constant(Symbol(), TrafficLight.Green)

const constrainToExample = rulr.union(
	rulr.object({
		required: {
			light: constrainToRedLight,
			redTimeSeconds: rulr.number,
		},
	}),
	rulr.object({
		required: {
			light: constrainToGreenLight,
			greenTimeSeconds: rulr.number,
		},
	})
)

type Example = rulr.Static<typeof constrainToExample>
// {
//   light: rulr.Constraint<typeof exampleSymbol, TrafficLight>,
//   redTimeSeconds: number,
// } | {
//   light: rulr.Constraint<typeof exampleSymbol, TrafficLight>
//   greenTimeSeconds: number,
// }

// Valid according to the compiler which is incorrect since it's clearly invalid
const example1: Example = {
	light: constrainToRedLight(TrafficLight.Red),
	greenTimeSeconds: 10,
}

You can see how this problem is solved by rulr.literal below.

import * as rulr from 'rulr'

enum TrafficLight {
	Red,
	Amber,
	Green,
}

const constrainToExample = rulr.union(
	rulr.object({
		required: {
			light: rulr.literal<TrafficLight.Red>(TrafficLight.Red),
			redTimeSeconds: rulr.number,
		},
	}),
	rulr.object({
		required: {
			light: rulr.literal<TrafficLight.Green>(TrafficLight.Green),
			greenTimeSeconds: rulr.number,
		},
	})
)

type Example = rulr.Static<typeof constrainToExample>
// {
//   light: TrafficLight.Red,
//   redTimeSeconds: number,
// } | {
//   light: TrafficLight.Green
//   greenTimeSeconds: number,
// }

// Invalid according to the compiler which is correct since it's clearly invalid
const example1: Example = {
	light: TrafficLight.Red,
	greenTimeSeconds: 10,
}