Skip to content

Commit 6733c5b

Browse files
Feature: valueof for string, numeric and boolean literals (microsoft#1877)
1 parent d53a6f2 commit 6733c5b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+739
-268
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@typespec/compiler",
5+
"comment": "Added new keyword `valueof` designed to request for a value type in a decorator parameter.",
6+
"type": "none"
7+
},
8+
{
9+
"packageName": "@typespec/compiler",
10+
"comment": "**BREAKING** Decorator API will not be marshalling values unless the parameter type is using `valueof`. `extern dec foo(target, value: string)` should be changed to `extern dec foo(target, value: valueof string)`.",
11+
"type": "none"
12+
},
13+
{
14+
"packageName": "@typespec/compiler",
15+
"comment": "**DEPRECATION** To make transition to valueof smoother if using a template parameter inside a decorator that is now using valueof the existing parmater constraint will still be compatible but emit a warning.",
16+
"type": "none"
17+
}
18+
],
19+
"packageName": "@typespec/compiler"
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@typespec/http",
5+
"comment": "Update decorators to use `valueof`",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@typespec/http"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@typespec/openapi",
5+
"comment": "Update decorators to use `valueof`",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@typespec/openapi"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@typespec/protobuf",
5+
"comment": "Update decorators to use `valueof`",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@typespec/protobuf"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@typespec/rest",
5+
"comment": "Update decorators to use `valueof`",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@typespec/rest"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@typespec/versioning",
5+
"comment": "Update decorators to use `valueof`",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@typespec/versioning"
10+
}

docs/extending-typespec/create-decorators.md

+31-9
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,37 @@ extern dec track(target: Model | Enum);
4040
A decorator parameter can be marked optional using `?`
4141

4242
```typespec
43-
extern dec track(target: Model | Enum, name?: StringLiteral);
43+
extern dec track(target: Model | Enum, name?: valueof string);
4444
```
4545

4646
### Rest parameters
4747

4848
A decorator's last parameter can be prefixed with `...` to collect all the remaining arguments. The type of that parameter must be an `array expression`
4949

5050
```typespec
51-
extern dec track(target: Model | Enum, ...names: StringLiteral[]);
51+
extern dec track(target: Model | Enum, ...names: valueof string[]);
52+
```
53+
54+
## Ask for a value type
55+
56+
It is common that decorators parameter will expect a value(e.g. a string or a number). However just using `: string` as the type will also allow a user of the decorator to pass `string` itself or a custom scalar extending string as well as union of strings.
57+
Instead the decorator can use `valueof <T>` to specify that it is expecting a value of that kind.
58+
59+
| Example | Description |
60+
| ----------------- | ---------------- |
61+
| `valueof string` | Expect a string |
62+
| `valueof float64` | Expect a float |
63+
| `valueof int32` | Expect a number |
64+
| `valueof boolean` | Expect a boolean |
65+
66+
```tsp
67+
extern dec tag(target: unknown, value: valueof string);
68+
69+
// bad
70+
@tag(string)
71+
72+
// good
73+
@tag("This is the tag name")
5274
```
5375

5476
## Implement the decorator in JS
@@ -63,7 +85,7 @@ Decorators can be implemented in JavaScript by prefixing the function name with
6385
// model.ts
6486
import type { DecoratorContext, Type } from "@typespec/compiler";
6587

66-
export function $logType(context: DecoratorContext, target: Type, name: string) {
88+
export function $logType(context: DecoratorContext, target: Type, name: valueof string) {
6789
console.log(name + ": " + targetType.kind);
6890
}
6991
```
@@ -92,13 +114,13 @@ model Dog {
92114

93115
### Decorator parameter marshalling
94116

95-
For certain TypeSpec types(Literal types) the decorator do not receive the actual type but a marshalled value. This is to simplify the most common cases.
117+
For certain TypeSpec types(Literal types) the decorator do not receive the actual type but a marshalled value if the decorator parmaeter type is a `valueof`. This is to simplify the most common cases.
96118

97-
| TypeSpec Type | Marshalled value in JS |
98-
| ---------------- | ---------------------- |
99-
| `StringLiteral` | `string` |
100-
| `NumericLiteral` | `number` |
101-
| `BooleanLiteral` | `boolean` |
119+
| TypeSpec Type | Marshalled value in JS |
120+
| ----------------- | ---------------------- |
121+
| `valueof string` | `string` |
122+
| `valueof numeric` | `number` |
123+
| `valueof boolean` | `boolean` |
102124

103125
for all the other types they are not transformed.
104126

0 commit comments

Comments
 (0)