Just as important as passing when things are right is failing when things are wrong.
Here are a few examples of the types of mistakes that literate-ts can catch:
This has a type error that isn’t marked in the source:
const nums = [1, 2, 3];
nums.push('four');
It should be:
const nums = [1, 2, 3];
nums.push('four');
// ~~~~~~ Argument of type '"four"' is not
// assignable to parameter of type 'number'.
If you have an error marked but TypeScript doesn’t produce it, that’s also a problem that requires investigation. For example:
const nums = [1, 2, 3];
let x;
// ~ Variable 'x' implicitly has an 'any' type.
x = 4;
nums.push(x);
The solution is to either remove the error comment:
const nums = [1, 2, 3];
let x;
x = 4;
nums.push(x);
or adjust the example to figure out why you aren’t getting the expected error. (For more on the behavior in this example, see Item 41: Understand Evolving any.)
literate-ts uses "type is" at the start of a comment to assert a type. If the type of the symbol does not match whatever is after "type is", character for character, then it’s considered a failure:
let x = 10; // type is number
const y = 10; // type is number
This will fail since the type of y
is inferred as 10
, not number
:
Failed type assertion for const y = 10; (tested y)
(The symbol tested is the last on which appears on the line, or the return type of a function if the last AST node is a function invocation.)
If you’re checking the output of a code sample, it has to match!
for (let i = 0; i < 3; i++) {
console.log(i);
}
definitely doesn’t log:
1 2 3
When you run this through literate-ts, you’ll get an error like
Actual output from Node did not match expected output.
If you open the detailed logs, you’ll see the diff:
Actual output from Node did not match expected output. Expected: 1 2 3 --- Actual: 0 1 2 Actual output matched expected.
You can also use this to check for (expected) Node.js runtime failures:
let city = 'new york city';
console.log(city.toUppercase());
will throw an error when you run it:
TypeError: city.toUppercase is not a function
When you use the -r
/ --replacements
flag, literate-ts will load additional code samples from that directory. These will be used in place of identically-named code samples in the text.
To make sure that these don’t get out of sync, they are compared subject to a few directives. For example, this replacement:
// HIDE
type LatLng = [number, number];
// END
function haversine(a: LatLng, b: LatLng): number {
// COMPRESS
return 0;
// END
}
Has to appear like this in the text:
function haversine(a: LatLng, b: LatLng): number {
// ...
}
If these don’t match up precisely, you’ll get an error. Here’s an example of one that fails:
function haversine(a: LatLng, b: LatLng): number {
// ...
}
You’ll need to run this sample with -r examples/asciidoc/replacements
to see the failure:
Inline sample does not match sample in source file
You can also define replacements inline in your file, presumably hidden away in a comment. This is done using the replace-with-id
directive. Here’s an example of that in action.
function calculateAge(birthDate: Date): number {
// ...
}
And here’s an example of that failing to match. Note that the replacement and the original may be defined in either order.
function calculateAge(birthDate: string): number {
// ...
}