I have following shape:
const type A = shape(
'b' => dict<string, int>,
);
How do I create this shape with empty dict? For example from this function
function getA(): A {
return shape(
'b' => ???
);
}
This is a part of the Hack array proposal
A dict array is a container mapping a valid arraykey to a value. This mirrors the behavior of the Map class. This will be an array at runtime with extra restrictions to allow it to be used safely like a Map from the type checkers perspective. This focuses mainly on the desired runtime behavior, but if there are questions for how it will interact with the type checker I'll be happy to discuss. Literal Constructor
A dict is constructed using the literal expression dict[].
$dict = dict[]; // Empty dict-array $dict = dict['a' => 1, 'b' => 2, 'c' => 3]; // dict-array of 3 elements
This is a static expression, so it can be used in a static initializer.
class C { public static dict<string, int> $dict = dict[ 'a' => 1, 'b' => 2, 'c' => 3, ]; }
You don't need to define the type when creating dictionaries ( dict[]
) or vectors ( vec[]
) as generics are ignored in runtime
Example :
function spamMessages(dict<string, string> $messages): void
{
foreach($messages as $user => $message) {
echo $user . ': ' . $message;
}
}
function listUsers(vec<string> $users): void
{
foreach($users as $user) {
echo '-' . $user;
}
}
$messages = dict[
'azjezz' => 'bring the cookies'
];
$users = vec[
'azjezz'
];
spamMessages($messages);
listUsers($users);
In this example, the type checker is smart enough to see that $message
have both keys and values of type string
so it won't raise any errors.
You can also create a dict array or a vector from a php-style array using the vec
and dict
helpers
$array = [
'a' => 1,
'b' => 'c'
];
$dict = dict($array);
In the above example, the type checker knows about the type of the keys in $array
, and since the dict
helper is declare as dict<Tk, Tv>(KeyedTraversable<Tk, Tv> $array): dict<Tk, Tv>
it knows that the returned dict array contains the same types for both keys and values.
Sometimes you may not be able to tell the type checker about the types of array keys and values.
Example:
$array = json_decode('path/to/file.json');
You know that the json files contains an array of string keys and values for example, but here type checker thinks that $array
is of type mixed
since there's no way to actually tell what's inside the file.
In order to get over this, you can use the as
operator to tell the type checker about $array
type
$array = json_decode('path/to/file.json') as array<_, _>;
Notice that here we used _
instead of string
and they type checker is going to assume that $array
now is of type array<arraykey, mixed>
, the reason is generics are not supported with the as
operator as of now, but this might changed in future so we can do as array<string, string>
Later you can create a dict out of that array :
$dict = dict($array);
If you for example know that there's no way for that file to contain anything beside string keys and values and want to force that type you can use the following helper to cast it to a dict of type dict<string, string>
, but I won't recommend it as it may cause an error while casting non-stringable
objects or resources to string.
// KeyedContainer = array, dict, maps and other keyed containers
function forceStringDict(KeyedContainer<arraykey, mixed> $container): dict<string, string>
{
$dict = dict[];
foreach($container as $k => $v) {
$dict[(string) $k] = (string) $v;
}
return $dict;
}
$dict = forceStringDict($dict);