can-define
Version:
Create observable objects with JS dot operator compatibility
171 lines (127 loc) • 4.27 kB
Markdown
{function|string} can-define.types.type type
can-define.behaviors
Converts a value set on an instance into an appropriate value.
`type(newValue, propertyName)`
Given the set value, transform it into a value appropriate to be set.
`type` is called before [can-define.types.set].
```js
import {DefineMap} from "can";
const Person = DefineMap.extend({
age: {
type: ( newValue, propertyName ) => {
return +newValue;
}
}
});
const p = new Person();
p.age = "25";
console.log( "p.age is a", typeof p.age, "The value is", p.age ); //-> "p.age is a number. The value is 25"
```
{*} newValue The value set on the property.
{String} propertyName The property name being set.
{*} The value that should be passed to `set` or (if there is no `set` property) the value to set on the map instance.
`"typeName"`
Sets the type to a named type in [can-define.types]. The default typeName is `"observable"`.
```js
import {DefineMap} from "can";
const Person = DefineMap.extend({
age: {
type: "number"
}
});
const p = new Person({ age: "5" });
console.log( p.age ) //-> 5
```
{String} typeName A named type in [can-define.types].
`{propDefinition}`
A [can-define.types.propDefinition] that defines an inline [can-define/map/map] type. For example:
```js
import {DefineMap} from "can";
const Home = DefineMap.extend({
address: {
type: {
street: "string",
city: { type: "string", default: "Chicago" }
}
}
});
const myHouse = new Home({
address: {
street: "101 Example St."
}
});
console.log( myHouse.serialize() ); //-> { address: {city: "Chicago", street: "101 Example St."} }
```
`[Type|propDefinition]`
Defines an inline [can-define/list/list] type that's an array of `Type` or inline `propDefinition` [can-define/map/map]
instances. For example:
```js
import {DefineMap} from "can";
import {Person} from "//unpkg.com/can-demo-models@5";
const List = DefineMap.extend({
people: {
type: [ Person ]
},
addresses: {
type: [ {
street: "string",
city: "string"
} ]
}
});
const myList = new List({
people: [ {first: "Justin", last: "Meyer"} ],
addresses: [ {street: "11 Example Ave.", city: "Chicago"} ]
});
console.log( myList.serialize() ); //-> {
// addresses: [ {city: "Chicago", street: "11 Example Ave."} ],
// people: [ {first: "Justin", last: "Meyer"} ]
// }
```
## Use
The `type` property specifies the type of the attribute. The type can be specified
as either:
- A type function that returns the type coerced value.
- A named type in [can-define.types].
- An object that gets converted into an inline `[can-define/map/map DefineMap]`.
- An array that gets converted to an inline `[can-define/list/list DefineList]`.
### Basic Example
The following example converts the `count` property to a number and the `items` property to an array.
```js
import {DefineMap} from "can";
const Map = DefineMap.extend( {
count: { type: "number" },
items: {
type( newValue ) {
if ( typeof newValue === "string" ) {
return newValue.split( "," );
} else if ( Array.isArray( newValue ) ) {
return newValue;
}
}
}
} );
const map = new Map();
map.assign({ count: "4", items: "1,2,3" });
console.log(map.count, map.items); //-> 4 ["1", "2", "3"]
```
### Preventing Arrays and Objects from Automatic Conversion
When an array value is set, it is automatically converted into a DefineList. Likewise, objects are converted into DefineMap instances. This behavior can be prevented like the following:
In this example when a user tries to set the `locations` property, the resulting value will remain an array.
```js
import {DefineMap, DefineList} from "can";
const MyMap = DefineMap.extend({
locations: {type: "any"},
});
const map = new MyMap( {locations: [1, 2, 3]} );
// locations is an array, not a DefineList
console.log( map.locations instanceof DefineList ); //-> false
console.log( Array.isArray( map.locations ) ); //-> true
```