Array of Nested Type: Why Does the Compiler Complain

Array of Nested Type: Why Does the Compiler Complain?

As you noted, it works with this syntax:

let arrayOfClassB: [ClassA.ClassB] = []

but the []() syntax works if we declare a typealias:

typealias InnerClass = ClassA.ClassB
let arrayOfAliasesOfClassB = [InnerClass]()

So I'd say it's a bug, let arrayOfClassB = [ClassA.ClassB]() should also work without needing a typealias.

Update: there's already an opened bug about this at Apple.

Why can't I use the short Array constructor syntax when creating an Array of a nested Struct?

It's just a hole in the language. After all, the [Type] syntax is just syntactic sugar; as you rightly say, if you use the real syntax with Array<Type>, or use [Type] but not as a constructor, there's no problem. You can also work around it with type alias:

struct Struct1 {
struct Struct2 {
var name: String?
}
}

typealias Struct2 = Struct1.Struct2

var struct2Array = [Struct2]()

Swift cannot create array of tuples containing a nested type

Yes, this is a bug as noted by this question.

Following the example of that Q & A, you can change the syntax of the way you create the array:

var attributes: [(attribute: String?, value: Gravl.Node)] = []

or

var attributes = Array<(attribute: String?, value: Gravl.Node)>()

In this case, you can also work around the issue by creating a typealias:

Example:

class Gravl {
enum Node {
case first, last
}
}

typealias Gravl_Node = Gravl.Node // work around Swift bug
var attributes = [(attribute: String?, value: Gravl_Node)]()

attributes.append((attribute: "hello", value: Gravl.Node.first))

Compiler complains about possible undefined in nested objects

Type guards (which is what you are using when you write if (objectVar[selector]) and expect the type to change based on the check) do not work with index access. This is documented in this and this issues. The reason for this is (as stated by @RyanCavanaugh in comments to the issue)

Declined due to performance reasons. Since it should almost always be possible to write const j = list[i] instead, this shouldn't be too burdensome.

As is stated above the recommendation is to use a local variable :

let objectVar: { [key: string]: number | undefined } = {a: 1};

const selector = "a";
const objectVar_selector = objectVar[selector];
if (objectVar_selector) {
objectVar_selector.toFixed; // Object is possible undefined? o0
}

SWIFT still fighting to assign a value to a nested array within a class

So following on from the comments above if you changed the code to be something along the lines of this you create the instance of the struct and add the values.

var jsonResult: HighScores?

if firstHighscore == 1 {
jsonResult = HighScores(Scores: 1, highscoreRecord: [HighscoreRecord(Rank: 1, Date: "your date", avDuration: 0.0, Score: 0, Tries: 0)])
}

once created you can add more highscorerecords to the array as needed, using the append method.

Java accessing local array from inner class

This is a usable trick in Java because the array (which is an object) you are using is never reassigned. You could do the same with the properties of an object.
If you changed properties of an object, you would still not have reassigned an object and it would remain "effectively final".
Reference:
Effectively final - Inner classes access

A side note: it is preferable to write arrays in the form: "int[] a" because they are more readable.

Typescript optional property type not working on nested prop when it's an array of another type

I got it to work with two small modifications:

The NullKeys type you defined kind of breaks with tuples. To make it work properly I added one small change.

type NullKeys<T extends Record<PropertyKey, any>> = {
[K in keyof T]: ExtractNull<T[K]> extends null
? K
: T[K] extends Record<PropertyKey, any>
? NullKeys<T[K]>
: never
}[keyof T & (T extends any[] ? `${bigint}` : string)] // <-- filter unwanted props

This will stop TypeScript from using all array properties like length and iterators from indexing this type.

type T0 = NullKeys<TestRoot>

// before:

// type T0 = number | "prop0" | "prop1" | "prop2" | (() => IterableIterator<"prop2">) | // (() => {
// copyWithin: boolean;
// entries: boolean;
// fill: boolean;
// find: boolean;
// findIndex: boolean;
// keys: boolean;
// values: boolean;
// }) | ... 90 more ... |

// after:

// type T0 = "prop0" | "prop1" | "prop2"

TypeScript will now complain about: Type instantiation is excessively deep and possibly infinite. But we can easily silence the compiler with this easy trick:

export type OptionalNulls<T extends Record<PropertyKey, any>> = {
[K in keyof T as Exclude<K, NullKeys<T>>]: T[K] extends Record<
PropertyKey,
any
>
? OptionalNulls<T[K]>
: T[K]
} & Partial<{
[K in keyof T as NullKeys<T> extends infer O ? Extract<K, O> : never]: T[K] // <-- silence compiler warning
}>

Playground


Yet I think you are overcomplicating the problem a bit. Here is a simpler solution:

type OptionalNulls<T> = {
[K in keyof T as null extends T[K] ? K : never]?: T[K] extends object
? OptionalNulls<T[K]>
: T[K]
} & {
[K in keyof T as null extends T[K] ? never : K]: T[K] extends object
? OptionalNulls<T[K]>
: T[K]
}

Playground



Related Topics



Leave a reply



Submit